Установите вложенное значение dict и создайте промежуточные ключи
Мне кажется, что я видел способ сделать это недавно. Скажем, у меня пустой dict, и я хочу установить значение в вложенном dict внутри этого пустого dict, но очевидно, что вложенный dict еще не создан. Есть ли 1-строчный способ создания промежуточных ключей? Это то, что я хочу сделать:
mydict = {}
mydict['foo']['bar']['foobar'] = 25
Если вы выполните этот код, вы получите исключение KeyError для 'foo'. Есть ли функция для создания промежуточных ключей?
Спасибо.
Ответы
Ответ 1
from collections import defaultdict
recursivedict = lambda: defaultdict(recursivedict)
mydict = recursivedict()
При доступе к mydict['foo']
он устанавливает mydict['foo']
в другой recursivedict
. Он фактически построит recursivedict
для mydict['foo']['bar']['foobar']
, но затем он будет выброшен, назначив это 25
.
Ответ 2
Альтернативный вариант - в зависимости от ваших применений - использовать кортежи как ключи вместо вложенных словарей:
mydict = {}
mydict['foo', 'bar', 'foobar'] = 25
Это будет отлично работать, если вы не захотите получить ветку дерева в любой точке (вы не можете получить mydict ['foo'] в этом случае).
Если вы знали, сколько слоев вложенности вы хотите, вы также можете использовать functools.partial
вместо лямбда.
from functools import partial
from collections import defaultdict
tripledict = partial(defaultdict, partial(defaultdict, dict))
mydict = tripledict()
mydict['foo']['bar']['foobar'] = 25
Что некоторые люди находят более читаемыми и быстрее создают экземпляры, чем эквивалентное лямбда-решение:
python -m timeit -s "from functools import partial" -s "from collections import defaultdict" -s "tripledefaultdict = partial(defaultdict, partial(defaultdict, dict))" "tripledefaultdict()"
1000000 loops, best of 3: 0.281 usec per loop
python -m timeit -s "from collections import defaultdict" -s "recursivedict = lambda: defaultdict(recursivedict)" "recursivedict()"
1000000 loops, best of 3: 0.446 usec per loop
Хотя, как всегда, оптимизация точки не существует, пока вы не знаете, есть ли узкое место, поэтому выберите наиболее полезную и читаемую информацию до того, что будет быстрее.
Ответ 3
Не уверен, зачем вам это нужно, но:
>>> from collections import defaultdict as dd
>>> mydict = dd(lambda: dd(lambda: {}))
>>> mydict['foo']['bar']['foobar'] = 25
>>> mydict
defaultdict(<function <lambda> at 0x021B8978>, {'foo': defaultdict(<function <lambda> at 0x021B8618>, {'bar': {'foobar': 25}})})