Вопрос-Ответ

Nested defaultdict of defaultdict

Вложенный defaultdict of defaultdict

Есть ли способ сделать defaultdict также значением по умолчанию для defaultdict? (т. Е. Рекурсивный defaultdict бесконечного уровня?)

Я хочу иметь возможность делать:

x = defaultdict(...stuff...)
x[0][1][0]
{}

Итак, я могу сделать x = defaultdict(defaultdict), но это только второй уровень:

x[0]
{}
x[0][0]
KeyError: 0

Есть рецепты, которые могут это сделать. Но можно ли это сделать просто, используя обычные аргументы defaultdict?

Обратите внимание, что здесь спрашивается, как выполнить рекурсивный defaultdict бесконечного уровня, поэтому он отличается от Python: defaultdict из defaultdict? , который заключался в том, как выполнить двухуровневый defaultdict.

Вероятно, в конечном итоге я просто использую шаблон bunch, но когда я понял, что не знаю, как это сделать, это меня заинтересовало.

Переведено автоматически
Ответ 1

Другие ответы здесь рассказывают вам, как создать defaultdict который содержит "бесконечно много" defaultdict, но они не учитывают то, что, я думаю, могло быть вашей первоначальной потребностью, которая заключалась в том, чтобы просто иметь двухуровневый defaultdict.

Возможно, вы искали:

defaultdict(lambda: defaultdict(dict))

Причины, по которым вы можете предпочесть эту конструкцию, следующие:


  • Это более явное, чем рекурсивное решение, и поэтому, вероятно, более понятно читателю.

  • Это позволяет "листу" defaultdict быть чем-то отличным от словаря, например,: defaultdict(lambda: defaultdict(list)) или defaultdict(lambda: defaultdict(set))

Ответ 2

Для произвольного количества уровней:

def rec_dd():
return defaultdict(rec_dd)

>>> x = rec_dd()
>>> x['a']['b']['c']['d']
defaultdict(<function rec_dd at 0x7f0dcef81500>, {})
>>> print json.dumps(x)
{"a": {"b": {"c": {"d": {}}}}}

Конечно, вы также могли бы сделать это с помощью лямбда-выражения, но я считаю, что лямбды менее удобочитаемы. В любом случае это выглядело бы так:

rec_dd = lambda: defaultdict(rec_dd)
Ответ 3

Для этого есть отличный трюк:

tree = lambda: defaultdict(tree)

Затем вы можете создать свой x с x = tree() помощью.

Ответ 4

Аналогично решению Бренбарна, но не содержит имя переменной tree дважды, поэтому работает даже после изменений в словаре переменных:

tree = (lambda f: f(f))(lambda a: (lambda: defaultdict(a(a))))

Затем вы можете создавать каждый новый x с x = tree() помощью.


Для def версии мы можем использовать область закрытия функции для защиты структуры данных от недостатка, из-за которого существующие экземпляры перестают работать, если tree имя rebound . Это выглядит так:

from collections import defaultdict

def tree():
def the_tree():
return defaultdict(the_tree)
return the_tree()
2024-01-01 16:58 python