I am trying to do something similar to this:
from collections import defaultdict
import hashlib
def factory():
key = 'aaa'
return { 'key-md5' : hashlib.md5('%s' % (key)).hexdigest() }
a = defaultdict(factory)
print a['aaa']
(actually, the reason why I need access to the key in the factory is not to compute an md5
, but for other reasons; this is just an example)
As you can see, in the factory I have no access to the key: I am just forcing it, which makes no sense whatsoever.
Is it possible to use defaultdict
in a way that I can access the key in the factory?
Defaultdict is a sub-class of the dictionary class that returns a dictionary-like object. The functionality of both dictionaries and defaultdict are almost same except for the fact that defaultdict never raises a KeyError. It provides a default value for the key that does not exists.
A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key. A defaultdict will never raise a KeyError. Any key that does not exist gets the value returned by the default factory.
__missing__
of defaultdict
does not pass key
to factory function.
If
default_factory
is notNone
, it is called without arguments to provide a default value for the given key, this value is inserted in the dictionary for the key, and returned.
Make your own dictionary class with custom __missing__
method.
>>> class MyDict(dict):
... def __init__(self, factory):
... self.factory = factory
... def __missing__(self, key):
... self[key] = self.factory(key)
... return self[key]
...
>>> d = MyDict(lambda x: -x)
>>> d[1]
-1
>>> d
{1: -1}
Unfortunately not directly, as defaultdict specifies that default_factory must be called with no arguments:
http://docs.python.org/2/library/collections.html#collections.defaultdict
But it is possible to use defaultdict as a base class that has the behavior you want:
class CustomDefaultdict(defaultdict):
def __missing__(self, key):
if self.default_factory:
dict.__setitem__(self, key, self.default_factory(key))
return self[key]
else:
defaultdict.__missing__(self, key)
This works for me:
>>> a = CustomDefaultdict(factory)
>>> a
defaultdict(<function factory at 0x7f0a70da11b8>, {})
>>> print a['aaa']
{'key-md5': '47bce5c74f589f4867dbd57e9ca9f808'}
>>> print a['bbb']
{'key-md5': '08f8e0260c64418510cefb2b06eee5cd'}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With