'Recursively turn all dicts inside a dict into a custom Dict class
Here's a class that returns None when a key doesn't exist (as opposed to crashing the entire application) and allows accessing keys like attributes:
class Dict(dict): # a dictionary that returns @None when a key doesn't exist (as opposed to crashing the entire application...) and allows accessing keys like attributes
def __init__( self, *args,**kwargs):
super(Dict,self).__init__(*args,**kwargs)
self.__dict__ = self # this allows accessing keys like attributes
def __getitem__(self, key,default=None):
return dict.get(self, key,default) # return None if the key exists not
def __getattribute__(self, attr): # return None if the attribute exists not
try: return object.__getattribute__(self,attr)
except AttributeError: return None
You can use it like so:
x = Dict({'a':0, 'b':1})
print(x['a'], x.a)
print(x['c'], x.c)
The problem is that this doesn't get applied recursively:
x = Dict({'a':{'aa':0x00}, 'b':1})
print(x['a'], x.a)
print(x.a['aa'])
print(x.a.aa) # AttributeError: 'dict' object has no attribute 'aa'
How can this be fixed.
Solution 1:[1]
Let's consider you requirements. First, you want something that returns None for missing keys, i.e. defaultdict -like behavior. However in real code, you'll discover that even defaultdict is often too much magic. Usually you want to know when keys are missing, instead of silently returning None, and instead of "crashing the entire application" you can just catch the exception:
try:
di[key]
except KeyError:
# handle missing key
Second, you want attribute access. That is understandable, since writing di.a is much nicer than di['a'] (especially on my Finnish keyboard and many others, where square brackets are behind a modifier key!) However, mixing both attribute access and item access (dict-like behavior) into the same object is problematic. For example, consider your Dict. What if someone does
di = Dict()
di['keys'] = ['C#', 'D']
di.keys() # TypeError: 'list' object is not callable
Now, your object no longer works properly as a dict. Same problem for any other dict method. I guess you could write __setitem__() and __setattribute__() guards that prevent overwriting dict methods, but it starts to get complicated.
In my opinion, you should decide whether you want item access or attribute access, and not try to implement both. If you want attributes, dataclasses are great (and you can implement __getattr__() to return None for missing attributes). If you want item access, just use a defaultdict.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jussi Nurminen |
