Re: Improvement to SimpleNamespace
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks. Raymond
On Wed, Apr 15, 2020 at 2:09 PM Raymond Hettinger <raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
My solution to that has usually been something along the lines of: def get(obj, path): for step in path.split("-"): obj = obj[step] return obj print(get(catalog, 'clothing-mens-shoes-extra_wide-quantity')) Will often be custom-tweaked to the situation, but the basic idea is the same. ChrisA
I've written AttributeDict a fair number of times. Each time I write it from scratch, which is only a few lines. And I only make a silly wore about 50% of the time when I do so. I wonder if a separate type in collections might be a more natural way to get the desired effect. I do recognize that such a type is very similar to SimpleNamespace, so get Raymond's concern with making a new thing for trivial change. But the *name* of the class should help with it's purpose IMO. On Wed, Apr 15, 2020, 12:04 AM Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Raymond _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/G5SJKRQ7... Code of Conduct: http://python.org/psf/codeofconduct/
On Tue, Apr 14, 2020 at 9:08 PM Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Yeah, I get that too. So maybe this should be limited to JSON? Could the stdlib json library be made to return objects that support this (maybe with an option)? -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
Raymond Hettinger wrote:
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
I can certainly agree with that sentiment, especially when working with something like GraphQL that tends to return deeply nested JSON objects. Repeatedly using [''] can get quite tiresome (and not look particularly great) with something like this: ``` for pr_edge in pr_json['data']['user']['pullRequests']['edges']: for comment_edge in pr_edge['node']['comments']['edges']: commenter = comment_edge['node']['author']['login'] ... ``` (Extracted from a personal side-project I worked on last year) On Wed, Apr 15, 2020 at 12:10 AM Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Raymond _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/G5SJKRQ7... Code of Conduct: http://python.org/psf/codeofconduct/
On 4/14/2020 9:25 PM, Guido van Rossum wrote:
On Tue, Apr 14, 2020 at 9:08 PM Raymond Hettinger <raymond.hettinger@gmail.com <mailto:raymond.hettinger@gmail.com>> wrote:
[GvR] > We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Yeah, I get that too. So maybe this should be limited to JSON? Could the stdlib json library be made to return objects that support this (maybe with an option)?
I replied in the issue, not noticing the discussion was happening here after getting interrupted with something else. But I use my implementation (uploaded to the issue) for many things besides JSON. Such a feature is just too practical not to be Pythonic.
On 14Apr2020 21:25, Guido van Rossum <guido@python.org> wrote:
On Tue, Apr 14, 2020 at 9:08 PM Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Yeah, I get that too. So maybe this should be limited to JSON? Could the stdlib json library be made to return objects that support this (maybe with an option)?
I find this feels slightly special purpose. Though admirably restrained. I think I dislike the need to detour thorough the json module to get such a feature. Like many others, I recently implemented one of these __getattr__+__getitem__ SimpleNamespaces. I'm hacking on some mappings which map dotted-names to values. So the natural implementation is dicts or dict subclasses. But I'm also feeding these to format strings, so I want to write: "Hi {dotted.name}" so I've made a nesting of SimpleNamespace so that I can use nice dotted a.b.c.d type names in the format string. And because I'm using .format_map, the top level namespace also supports __getitem__. Now, my dict subclass has a .ns() method returning one of the above SimpleNamespace subclasses, but I can readily imagine a utility function in collection that made such a thing. Restricting that to only work via some contrived path through the JSON module seems... clunky. Cheers, Cameron Simpson <cs@cskk.id.au>
On Tue, Apr 14, 2020 at 9:26 PM David Mertz <mertz@gnosis.cx> wrote:
I've written AttributeDict a fair number of times. Each time I write it from scratch, which is only a few lines. And I only make a silly wore about 50% of the time when I do so.
I've also written it a number of times, and never found a way to do it that I was really happy with. (In particular, converting all sub-dicts into AttributeDict is necessary to support a.b.c-style access, but if c is itself a dict, then you end up leaking AttributeDict objects into other parts of the code that might just be expecting a regular dict.) These days I've given up on that approach and use Mahmoud's 'glom' library instead: https://glom.readthedocs.io/ It has a ton of super-fancy features, but mostly I ignore those and just write stuff like 'glom(json_obj, "a.b.c")' or maybe 'glom(json_obj, "a.b.c", default=None)'. Like anything there are probably trade-offs and situations where something like AttributeDict is better, but figured I'd throw that out there as another option to consider. -n -- Nathaniel J. Smith -- https://vorpus.org
On 4/14/2020 10:09 PM, Cameron Simpson wrote:
On 14Apr2020 21:25, Guido van Rossum <guido@python.org> wrote:
On Tue, Apr 14, 2020 at 9:08 PM Raymond Hettinger < raymond.hettinger@gmail.com> wrote:
[GvR]
We should not try to import JavaScript's object model into Python.
Yes, I get that. Just want to point-out that working with heavily nested dictionaries (typical for JSON) is no fun with square brackets and quotation marks.
Yeah, I get that too. So maybe this should be limited to JSON? Could the stdlib json library be made to return objects that support this (maybe with an option)?
I find this feels slightly special purpose. Though admirably restrained. I think I dislike the need to detour thorough the json module to get such a feature.
Like many others, I recently implemented one of these __getattr__+__getitem__ SimpleNamespaces. I'm hacking on some mappings which map dotted-names to values. So the natural implementation is dicts or dict subclasses. But I'm also feeding these to format strings, so I want to write:
"Hi {dotted.name}"
so I've made a nesting of SimpleNamespace so that I can use nice dotted a.b.c.d type names in the format string. And because I'm using .format_map, the top level namespace also supports __getitem__.
Now, my dict subclass has a .ns() method returning one of the above SimpleNamespace subclasses, but I can readily imagine a utility function in collection that made such a thing.
Restricting that to only work via some contrived path through the JSON module seems... clunky.
Cheers, Cameron Simpson <cs@cskk.id.au>
Interesting comments. So .ns allows you to convert a nested dict to a dotted one "on demand" but the initial conversion only needs to do the top level object? That sounds similar to the glom that Nathaniel brought to the attention of this thread, which I hadn't found before. But glom requires bulkier syntax. When I read his example, I thought to myself "What if one could write his 'glom(json_obj, "a.b.c")' example as json_obj['a.b.c'] or better as non_json_obj.a.b.c ? I can imagine an implementation of my first "what-if" fully in the top-level object, but not of the second (but my internals imagination is probably limited). Indeed, many of my use-cases are non-json, although a bunch are json also.
On 14Apr2020 23:08, Glenn Linderman <v+python@g.nevcal.com> wrote:
On 4/14/2020 10:09 PM, Cameron Simpson wrote:
Like many others, I recently implemented one of these __getattr__+__getitem__ SimpleNamespaces. I'm hacking on some mappings which map dotted-names to values. So the natural implementation is dicts or dict subclasses. But I'm also feeding these to format strings, so I want to write:
"Hi {dotted.name}"
so I've made a nesting of SimpleNamespace so that I can use nice dotted a.b.c.d type names in the format string. And because I'm using .format_map, the top level namespace also supports __getitem__.
Now, my dict subclass has a .ns() method returning one of the above SimpleNamespace subclasses, but I can readily imagine a utility function in collection that made such a thing. [...]
The below is something of a digression from the main topic, so before digressing let me prefix with: I'm with Raymond here. I think my position is that unlike most classes, SimpleNamespace has very simple semantics, and no __getitem__ facility at all, so making __getitem__ map to __getattr__ seems low impact. Now the digression:
Interesting comments. So .ns allows you to convert a nested dict to a dotted one "on demand" but the initial conversion only needs to do the top level object?
In principle, yes. As it happens all of the subnamespaces are this class as well, so one can __getitem__ on them too. I just... don't need to in a format string. As you might imagine this has sort of evolved from my initial problem of accessing the dotted.name values in a format string, and it still has some iteration to go there. str.format() requires completely filled out keyword arguments, but str.format_map() accepts any mapping, so __getitem__ can do whatever one wants. In my base class it is a thin wrapper around getattr(). Because I'm starting with a flat dict like: { 'a': 1 'b': 2, 'b.c': 3, 'b.d': 4, 'b.d.e': 5, } the .ns() utility method constructs a complete nested tree of SimpleNamespace objects.
That sounds similar to the glom that Nathaniel brought to the attention of this thread, which I hadn't found before. But glom requires bulkier syntax. When I read his example, I thought to myself "What if one could write his 'glom(json_obj, "a.b.c")' example as json_obj['a.b.c']
Hah, I've got one of those, too, almost :-) I've got a cs.sqlalchemy_utils module with a get_json_field(column_value, field_name) function (it has a "set" friend). It was intended to access a JSON blob database column, and the field_name it accepts is a dotted name used to traverse a nesting of dicts. I see its signature looks like glom().
or better as non_json_obj.a.b.c ? I can imagine an implementation of my first "what-if" fully in the top-level object, but not of the second (but my internals imagination is probably limited).
Nested dicts are a natural thing, and what you get from nested JSON structures, particularly since JavaScript objects _are_ dicts, and the attribute stuff is almost syntactic sugar.
Indeed, many of my use-cases are non-json, although a bunch are json also.
My use case for the .ns() stuff is nonJSON. One of the reasons my dict-subclass has a .ns() method to create a set of nested namespaces is that an ordinary class has plenty of method names which will overlap dict element names. So making the dict's __getitem__ available via __getattr__ leads to trouble as soon as a key matches a dict method name. For this reason I gave it a separate .ns() method to construct the SimpleNamespaces, which are a _transcription_ of the original values. Cheers, Cameron Simpson <cs@cskk.id.au>
Apologies to other list members. Glenn, we were having a conversation off list and there's no evidence my replies reached you. Could you have a glance in your spam (if you have such a thing) to see if my messages are lying there idle? From the 15th and 20th of April. GMail certainly seems to have a personal dislike for me, and I'm fearing something similar may be at play for you. Again, my apologies to other list members. Thanks, Cameron Simpson <cs@cskk.id.au>
participants (8)
-
Cameron Simpson
-
Chris Angelico
-
David Mertz
-
Glenn Linderman
-
Guido van Rossum
-
Kyle Stanley
-
Nathaniel Smith
-
Raymond Hettinger