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>