【问题标题】:Set nested dict value and create intermediate keys设置嵌套字典值并创建中间键
【发布时间】:2012-04-18 21:43:35
【问题描述】:

我觉得我最近看到了一种方法。假设我有一个空字典,我想在该空字典内的嵌套字典中设置一个值,但显然该嵌套字典尚未创建。是否有一种单行方式来创建中间键?这就是我想做的:

mydict = {}
mydict['foo']['bar']['foobar'] = 25

如果您执行此代码,您将收到“foo”的 KeyError 异常。有创建中间键的功能吗?

谢谢。

【问题讨论】:

标签: python dictionary


【解决方案1】:
from collections import defaultdict
recursivedict = lambda: defaultdict(recursivedict)
mydict = recursivedict()

当您访问mydict['foo'] 时,它会将mydict['foo'] 设置为另一个recursivedict。它实际上也会为mydict['foo']['bar']['foobar'] 构造一个recursivedict,但随后将其分配给25 会被丢弃。

【讨论】:

  • 这正是我记得读过的内容——谢谢。
  • 这可能会在mydict['foo'] = 15⏎ mydict['foo']['bar']['foobar'] = 25 上中断。在大型代码库中,OP 无法记住他之前分配的值。
  • @itsneo 是的。我不认为有什么好办法。您必须使 __getitem__ 围绕存储的元素返回包装器,覆盖该元素的 __getitem__,这会使将列表或其他任何内容放入字典中变得很棘手。
  • 太棒了!谢谢,这就是我要找的机器人!
【解决方案2】:

另一种选择 - 根据您的用途,使用元组作为键而不是嵌套字典:

mydict = {}
mydict['foo', 'bar', 'foobar'] = 25

除非您想在任何时候获取树的分支(在这种情况下您无法获取 mydict['foo']),否则这将非常有效。

如果您知道要嵌套多少层,也可以使用functools.partial 代替 lambda。

from functools import partial
from collections import defaultdict

tripledict = partial(defaultdict, partial(defaultdict, dict))
mydict = tripledict()
mydict['foo']['bar']['foobar'] = 25

有些人觉得这比同等的基于 lambda 的解决方案更具可读性,并且创建实例的速度更快:

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

尽管与往常一样,在您知道存在瓶颈之前进行优化是没有意义的,所以在最快的之前选择最有用和可读的。

【讨论】:

  • 有趣的东西。我从没想过使用元组作为字典键。虽然这对我没有帮助,但它肯定很有用——谢谢!
  • 当然,使用基于元组的解决方案可以通过prefix = ('foo', 'bar'); l = len(prefix); branch = { k[l:]: v for k, v in mydict.items() if k[:l] == prefix} 之类的方式获取树枝——尽管这需要遍历所有键。
  • @Dougal 是的,在这一点上,你最好只使用嵌套的dicts。
  • @Lattyware 嗯,取决于。通常是的,但是如果您需要进行大量的深度元素访问并且很少需要创建分支,那么使用元组方法可能会更快(因为每次访问只进行一个 dict 散列)。不过,我觉得在 OP 的情况下,这并不是一个真正的考虑因素。
  • @Dougal 我实际上看到 [a question](stackoverflow.com/questions/10182841/two-dimensional-vs-one-dimensional-dictionary-efficiency-in-python) 最近关于让我感到惊讶的问题,似乎嵌套的字典实际上比元组更快。
【解决方案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}})})

【讨论】:

  • 这只让你嵌套到三层;您希望函数是递归的,就像在my answer 中一样,以便能够继续运行。
  • @Dougal:当我写这篇文章时,你的回答并没有这么说。
  • @Dougal:如果OP需要三层深度,那就足够了。
  • @StevenRumbalski ...显然,是的,但考虑到 OP 只询问“嵌套字典”,这是一个奇怪的要求。是的,马特,我在你回答的同时编辑了我的答案;我的帖子旨在指出您回答的一个缺点,而不是说“我已经发布了一个更好的你这个笨蛋”。 :p
  • 这个解决方案没有错,但我可能需要深入 3 个级别,所以 Dougal 的答案更好。谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
相关资源
最近更新 更多