I want to create a python dictionary that returns me the key value for the keys are missing from the dictionary.
Usage example:
dic = smart_dict()
dic['a'] = 'one a'
print(dic['a'])
# >>> one a
print(dic['b'])
# >>> b
I want to create a python dictionary that returns me the key value for the keys are missing from the dictionary.
Usage example:
dic = smart_dict()
dic['a'] = 'one a'
print(dic['a'])
# >>> one a
print(dic['b'])
# >>> b
dict
s have a__missing__
hook for this:Why don't you just use
Sure, you can subclass
dict
as others point out, but I find it handy to remind myself every once in a while thatget
can have a default value!If you want to have a go at the
defaultdict
, try this:except... well:
AttributeError: ^collections.defaultdict^object attribute '__missing__' is read-only
, so you will have to subclass:The first respondent mentioned
defaultdict
, but you can define__missing__
for any subclass ofdict
:Also, I like the second respondent's approach:
Congratulations. You too have discovered the uselessness of the standard
collections.defaultdict
type. If that execrable midden heap of code smell offends your delicate sensibilities as much as it did mine, this is your lucky StackOverflow day.Thanks to the forbidden wonder of the 3-parameter variant of the
type()
builtin, crafting a non-useless default dictionary type is both fun and profitable.What's Wrong with dict.__missing__()?
Absolutely nothing, assuming you like excess boilerplate and the shocking silliness of
collections.defaultdict
– which should behave as expected but really doesn't. To be fair, Jochen Ritzel's accepted solution of subclassingdict
and implementing the optional__missing__()
method is a fantastic workaround for small-scale use cases only requiring a single default dictionary.But boilerplate of this sort scales poorly. If you find yourself instantiating multiple default dictionaries, each with their own slightly different logic for generating missing key-value pairs, an industrial-strength alternative automating boilerplate is warranted.
Or at least nice. Because why not fix what's broken?
Introducing DefaultDict
In less than ten lines of pure Python (excluding docstrings, comments, and whitespace), we now define a
DefaultDict
type initialized with a user-defined callable generating default values for missing keys. Whereas the callable passed to the standardcollections.defaultdict
type uselessly accepts no parameters, the callable passed to ourDefaultDict
type usefully accepts the following two parameters:Given this type, solving sorin's question reduces to a single line of Python:
Sanity. At last.
Code or It Didn't Happen
The key ...get it, key? to this arcane wizardry is the call to the 3-parameter variant of the
type()
builtin:This single line dynamically generates a new
dict
subclass aliasing the optional__missing__
method to the caller-defined callable. Note the distinct lack of boilerplate, reducingDefaultDict
usage to a single line of Python.Automation for the egregious win.
Subclass
dict
's__getitem__
method. For example, How to properly subclass dict and override __getitem__ & __setitem__I agree this should be easy to do, and also easy to set up with different defaults or functions that transform a missing value somehow.
Inspired by Cecil Curry's answer, I asked myself: why not have the default-generator (either a constant or a callable) as a member of the class, instead of generating different classes all the time? Let me demonstrate:
How does it work? Not so difficult:
Of course, one can debate whether one wants to allow changing the default-function after initialisation, but that just means removing
@default.setter
and absorbing its logic into__init__
.Enabling introspection into the current (constant) default value could be added with two extra lines.