clj-python / libpython-clj

Python bindings for Clojure
Eclipse Public License 2.0
1.08k stars 68 forks source link

keyword lookup on NamedTuple #202

Closed shaunlebron closed 2 years ago

shaunlebron commented 2 years ago

I believe a NamedTuple in python supports two types of lookups: attribute name or index.

Right now, I have to use (py.- nt :foo) whereas (:foo nt) does not work and returns nil. I believe this is because the jvm bridge is not able to treat a namedtuple as both a dict and a tuple. Is this possible?

Thank you!

_(I deleted a followup comment about (py. nt _asdict) not working, but it was my error in not requiring "py.")_

jjtolton commented 2 years ago

Clojure Keywords are not currently polymorphic with python getattr.

On Fri, Apr 22, 2022 at 1:23 AM shaun @.***> wrote:

I believe a NamedTuple https://docs.python.org/3.3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields in python supports two types of lookups: attribute name or index.

Right now, I have to use (py.- nt :foo) but (:foo nt) returns nil. I believe this is because the jvm bridge is not able to treat a namedtuple as both a dict and a tuple. Is this possible? Thanks!

— Reply to this email directly, view it on GitHub https://github.com/clj-python/libpython-clj/issues/202, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACPJX42LLX3M4TWEMMF45ILVGIZWZANCNFSM5UBF5LRA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

jjtolton commented 2 years ago

Did you require “py.”?

On Fri, Apr 22, 2022 at 1:35 AM shaun @.***> wrote:

Also, while trying to convert a namedtuple to a dict using ._asdict() https://docs.python.org/3/library/collections.html#collections.somenamedtuple._asdict, I had a peculiar run-in with the following two expressions which I presumed would be equivalent:

  • (py. nt _asdict) fails with "unable to resolve classname: py"
  • ((py.- nt _asdict)) succeeds

— Reply to this email directly, view it on GitHub https://github.com/clj-python/libpython-clj/issues/202#issuecomment-1106028244, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACPJX43NDCFWRAR4HMB7AHLVGI3BPANCNFSM5UBF5LRA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

shaunlebron commented 2 years ago

Thanks. Is there a way to make keywords polymorphic to getattr from the user side?

jjtolton commented 2 years ago

(moved to comment below b/c apparently markdown doesn't work from email)

jjtolton commented 2 years ago

Do you mean extending libpython-clj itself? We do have hooks into the datafy/nav paradigm, which would be one option. Checkout the code here: https://github.com/clj-python/libpython-clj/blob/master/src/libpython_clj2/require.clj#L352

You could probably do something like:


(defmethod pydafy 'builtins.NamedTuple [nt] 
;; code to convert named tuple -> clojure, possibly in conjunction 
 ;; with a Clojure NamedTuple protocol that extends `get` 
... ) 

note that once you've extended with pydafy, you can then use standard Clojure datafy function. This would result in code that might look like, at a low level,


(:foo (datafy nt))

There are lower level hooks available for performant marshalling of data types from Python, but that would be a broader feature request discussion.

shaunlebron commented 2 years ago

Thanks so much for the example, I was not familiar with datafy. Glad to know this.

And just to share here, I missed the following distinction in Python (since they’re both equivalent in JS):

So I understand your original response now, that keywords map to getitem, whereas py.- is to be used for getattr. I’ll just use it that way to not hide what's happening in python. Thank you!

jjtolton commented 2 years ago

Great point! We're always discussing the right balance to strike in how much to hide/expose. Always open to suggestions, thank you for your input!

On Fri, Apr 22, 2022 at 1:15 PM shaun @.***> wrote:

Thanks so much for the example, I was not familiar with datafy. Glad to know this.

And just to share here, I missed the following distinction in Python (since they’re both equivalent in JS):

  • getitem is for foo['bar'] = foo.get('bar')
  • getattr is for foo.bar = getattr(foo, 'bar')

So I understand your original response now, that keywords map to getitem, whereas py.- is to be used for getattr. I’ll just use it that way to not hide what's happening in python. Thank you!

— Reply to this email directly, view it on GitHub https://github.com/clj-python/libpython-clj/issues/202#issuecomment-1106708522, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACPJX44SHSJV2VVHVJTJSQLVGLNCHANCNFSM5UBF5LRA . You are receiving this because you commented.Message ID: @.***>

shaunlebron commented 2 years ago

Thanks. I don't really know what I'm doing yet, but I can't believe this project exists AND works flawlessly so far. Thanks for all your work 🙏