I find it more convenient to access dict keys as obj.foo
instead of obj['foo']
, so I wrote this snippet:
class AttributeDict(dict): def __getattr__(self, attr): return self[attr] def __setattr__(self, attr, value): self[attr] = value
However, I assume that there must be some reason that Python doesn't provide this functionality out of the box. What would be the caveats and pitfalls of accessing dict keys in this manner?
We can also fetch the key from a value by matching all the values using the dict. item() and then print the corresponding key to the given value.
AttrDict , Attribute Dictionary, is the exact same as a python native dict , except that in most cases, you can use the dictionary key as if it was an object attribute instead. This allows users to create container objects that looks as if they are class objects (as long as the user objects the proper limitations).
Since this question was asked almost ten years ago, quite a bit has changed in Python itself since then.
While the approach in my original answer is still valid for some cases, (e.g. legacy projects stuck to older versions of Python and cases where you really need to handle dictionaries with very dynamic string keys), I think that in general the dataclasses introduced in Python 3.7 are the obvious/correct solution to vast majority of the use cases of AttrDict
.
The best way to do this is:
class AttrDict(dict): def __init__(self, *args, **kwargs): super(AttrDict, self).__init__(*args, **kwargs) self.__dict__ = self
Some pros:
.keys()
work just fine. Unless - of course - you assign some value to them, see below)AttributeError
instead of KeyError
Cons:
.keys()
will not work just fine if they get overwritten by incoming dataE1123(unexpected-keyword-arg)
and E1103(maybe-no-member)
__dict__
.__dict__
would need to be "just a plain dict", so we can assign any subclass of dict()
to the internal dictionary.AttrDict()
instance we are instantiating (as we are in __init__
).super()
's __init__()
method we made sure that it (already) behaves exactly like a dictionary, since that function calls all the dictionary instantiation code.As noted in the "cons" list, this combines the namespace of stored keys (which may come from arbitrary and/or untrusted data!) with the namespace of builtin dict method attributes. For example:
d = AttrDict() d.update({'items':["jacket", "necktie", "trousers"]}) for k, v in d.items(): # TypeError: 'list' object is not callable print "Never reached!"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With