Reputation: 273
my_dict = {'a': 1}
I wish for my_dict['a']
to behave the same as my_dict.get('a')
That way, if I do my_dict['b']
, I will not raise an error but get the default None
value, the same way you would get it from my_dict.get('b')
In the case of my_dict = {'a': {'b': 2}}
I could do my_dict['a']['b']
and it would act as my_dict.get('a').get('b')
When doing my_dict['b'] = 2
it will act same as my_dict.update({'b': 2})
Is it possible to do so that I will not have to inherit from dict?
Upvotes: 0
Views: 64
Reputation: 1123400
You can use a collections.defaultdict()
object to add a new value to the dictionary each time you try to access a non-existing key:
>>> from collections import defaultdict
>>> d = defaultdict(lambda: None)
>>> d['a'] is None
True
>>> d
defaultdict(<function <lambda> at 0x10f463e18>, {'a': None})
If you don't want the key added, create a subclass of dict
that implements the __missing__
method:
class DefaultNoneDict(dict):
def __missing__(self, key):
return None
This explicitly won't add new keys:
>>> d = DefaultNoneDict()
>>> d['a'] is None
True
>>> d
{}
If you wanted to chain .get()
calls, you'll have to return an empty dictionary instead, otherwise dict.get(keyA).get(keyB)
will fail with an attribute error (the first None
returned won't have a .get()
method).
Generally speaking, it is better to stick to the default type and be explicit. There is nothing wrong with:
value = some_d.get(outer, {}).get(inner)
Using a defaultdict
or a dict
subclass with custom __missing__
hook have a downside: they will always produce a default when the key is missing, even when you accidentally produced incorrect keys somewhere else in your code. I often opt for an explicit dict.get()
or dict.setdefault()
codepath over defaultdict
precisely because I want a non-existing key to produce an error in other parts of my project.
Upvotes: 5