Есть ли разумный способ передать ключ defaultdict default_factory?
В классе есть конструктор, который принимает один параметр:
class C(object):
def __init__(self, v):
self.v = v
...
Где-то в коде полезно для значений в dict знать свои ключи.
Я хочу использовать defaultdict с ключом, переданным значениям по умолчанию для новорожденных:
d = defaultdict(lambda : C(here_i_wish_the_key_to_be))
Любые предложения?
Ответы
Ответ 1
Он вряд ли квалифицируется как умный, но подклассификация - ваш друг:
class keydefaultdict(defaultdict):
def __missing__(self, key):
if self.default_factory is None:
raise KeyError( key )
else:
ret = self[key] = self.default_factory(key)
return ret
d = keydefaultdict(C)
d[x] # returns C(x)
Ответ 2
Нет, нет.
Реализация defaultdict
не может быть настроена на передачу отсутствующего key
в default_factory
из коробки. Ваш единственный вариант - реализовать свой собственный подкласс defaultdict
, как было предложено @JochenRitzel, выше.
Но это не "умный" или почти такой же чистый, как стандартное решение библиотеки (если оно существует). Таким образом, ответ на ваш сжатый, да/нет вопрос явно "нет".
Слишком плохо, что в стандартной библиотеке отсутствует такой часто требуемый инструмент.
Ответ 3
Я не думаю, что вам нужно defaultdict
здесь вообще. Почему бы просто не использовать метод dict.setdefault
?
>>> d = {}
>>> d.setdefault('p', C('p')).v
'p'
Это, конечно же, создаст много экземпляров C
. Если это проблема, я думаю, что более простой подход будет делать:
>>> d = {}
>>> if 'e' not in d: d['e'] = C('e')
Это было бы быстрее, чем defaultdict
или любой другой альтернативы, насколько я могу видеть.
ETA относительно скорости теста in
против использования предложения try-except:
>>> def g():
d = {}
if 'a' in d:
return d['a']
>>> timeit.timeit(g)
0.19638929363557622
>>> def f():
d = {}
try:
return d['a']
except KeyError:
return
>>> timeit.timeit(f)
0.6167065411074759
>>> def k():
d = {'a': 2}
if 'a' in d:
return d['a']
>>> timeit.timeit(k)
0.30074866358404506
>>> def p():
d = {'a': 2}
try:
return d['a']
except KeyError:
return
>>> timeit.timeit(p)
0.28588609450770264