Building your own defaultdict
Python has a type called defaultdict, which you may know about:
- from collections import defaultdict
-
- players = ['Janet', 'Tina', 'Cindy']
- points = defaultdict(int)
-
- # Janet scores a point!
- points['Janet'] += 1
- # Tina scores THREE points!
- points['Tina'] += 3
-
- for player in players:
- print(player, points[player])
Run this program, and here's the output:
- Janet 1
- Tina 3
- Cindy 0
See how we used "+=" for Janet and Tina, and Cindy never got referenced at all. But a default value of 0 was auto-magically inserted in "points" for each of them.
If there were no defaultdict, how would you make your own?
There are several ways to do it. Here is one:
- from collections import UserDict
-
- class mydefaultdict(UserDict):
- def __init__(self, default_factory):
- self.default_factory = default_factory
- super().__init__(self)
- def __getitem__(self, key):
- if key not in self.data:
- self.data[key] = self.default_factory()
- return self.data[key]
"mydefaultdict" works just like the built-in defaultdict. What's going on:
We are using a mixin class, called UserDict - which coincidentally also happens to be in the collections module.
This class adds a member variable, called "self.data", which is a dictionary. And it also adds the magic methods that make square brackets work.
We're redefining one of them here, __getitem__()
, which gets called when you look up a value for a key (as opposed to inserting/assigning).
Because we're also stashing something on self called "default_factory". Which it turns out is a callable - i.e., something that can be called like a function. And see how we call it in __getitem__()
, to generate the new value.
Now, there's kind of a lot going on here. And there's a lot you can build on the core ideas.
Which is why I uploaded a 50 minute video about it.
And there are other ways we can extend the concept of a dict...
For example, maybe you need an "auto-sorting" dict, which sorts its keys when you use it in a for loop...
Or maybe you need something like a dict, but it has multiple values for a key, instead of just one...
Or some other dict-like thingy that works some other weird but necessary way in your program...
And if you'd like to be the kind of Pythonista who can spin up code for things like this, in less time than it took you to read this far...
Powerful Python Bootcamp turns you into that kind of Pythonista.