Доступ к ключу в factory defaultdict

Я пытаюсь сделать что-то похожее на это:

from   collections import defaultdict
import hashlib

def factory():
    key = 'aaa'
    return { 'key-md5' : hashlib.md5('%s' % (key)).hexdigest() }

a = defaultdict(factory)
print a['aaa']

(на самом деле, причина, по которой мне нужен доступ к ключу в factory, заключается не в вычислении md5, а по другим причинам, это просто пример)

Как вы можете видеть, в factory у меня нет доступа к ключу: я просто заставляю его, что не имеет никакого смысла.

Можно ли использовать defaultdict таким образом, чтобы я мог получить доступ к ключу в factory?

Ответ 1

__missing__ defaultdict не передает функцию key в factory.

Если default_factory не None, он называется без аргументов. укажите значение по умолчанию для данного ключа, это значение вставляется в словарь для ключа и возвращен.

Создайте свой собственный класс словаря с помощью настраиваемого метода __missing__.

>>> 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}

Ответ 2

К сожалению, не напрямую, поскольку defaultdict указывает, что default_factory должен быть вызван без аргументов:

http://docs.python.org/2/library/collections.html#collections.defaultdict

Но можно использовать defaultdict как базовый класс, у которого есть поведение, которое вы хотите:

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)

Это работает для меня:

>>> a = CustomDefaultdict(factory)
>>> a
defaultdict(<function factory at 0x7f0a70da11b8>, {})
>>> print a['aaa']
{'key-md5': '47bce5c74f589f4867dbd57e9ca9f808'}
>>> print a['bbb']
{'key-md5': '08f8e0260c64418510cefb2b06eee5cd'}