Trying to access a non-existent key using this notation raises a KeyError
: dict[key]
. An easy workaround for this is to use get(key)
instead, which returns None
if key
isn't found, or get(key, default)
which returns default
if key
isn't found.
>>> d = {}
>>> d
{}
>>> d["x"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'x'
>>> d.get("x")
>>> d
{}
>>> d.get("x","y")
'y'
>>> d
{}
>>>
But what if you want to not only return a default if the key is missing, but also assign that default to the specified key in the dict? There are a couple of ways to do that.
1. setdefault
setdefault(key[, default])
If key is in the dictionary, return its value. If not, insert key with a value of default and return default.
default
defaults toNone
.
>>> d
{}
>>> d.setdefault("x","y")
'y'
>>> d
{'x': 'y'}
>>>
2. defaultdict
class collections.defaultdict(default_factory=None, /[, ...])
The first argument provides the initial value for the default_factory attribute; it defaults to
None
. All remaining arguments are treated the same as if they were passed to the dict constructor, including keyword arguments.
>>> from collections import defaultdict
>>> i = defaultdict(int)
>>> i
defaultdict(<class 'int'>, {})
>>> i["x"]
0
>>> i
defaultdict(<class 'int'>, {'x': 0})
>>> i["y"]
0
>>> i
defaultdict(<class 'int'>, {'x': 0, 'y': 0})
>>>
Note that no KeyError
is raised despite the key not existing at first. Instead, the key is created with the default value of the type passed into defaultdict
, in this case 0
for int
. If we used list
instead, the default value would be []
, an so on.
Further reading:
- defaultdict Examples
- Use cases for the 'setdefault' dict method (vs defaultdict)
3. Implement __missing__
This is actually what defaultdict
does behind the scenes. Use this when defaultdict
doesn't fit your usecase.
>>> class M(dict):
... def __missing__(self, key):
... value = "my default value"
... self[key] = value
... return value
...
>>>
>>> m = M()
>>> m
{}
>>> m["x"]
'my default value'
>>> m
{'x': 'my default value'}
>>> m["y"]
'my default value'
>>> m
{'x': 'my default value', 'y': 'my default value'}
>>>