繁体   English   中英

Python如何使用defaultdict创建列表dict的dict

[英]Python how to create a dict of dict of list with defaultdict

如何使用 defaultdict 创建列表 dict 的 dict? 我收到以下错误。

>>> from collections import defaultdict
>>> a=defaultdict()
>>> a["testkey"]=None
>>> a
defaultdict(None, {'testkey': None})
>>> a["testkey"]["list"]=[]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object does not support item assignment

这有点棘手。 您创建 defaultdicts 的 defaultdict,如下所示:

defaultdict(lambda: defaultdict(list))

比使用lambda略快:

defaultdict(defaultdict(list).copy)

这与wim 的答案具有相同的可观察行为,但避免使用lambda以支持在 C 中实现的(在 CPython 中)绑定内置方法,这意味着默认值生成不必执行任何 Python 字节代码或查找任何名称,并且运行速度略快。 在 CPython 3.5 上的微基准测试中,当密钥在访问时不存在时,这种方式所支付的成本似乎比其他等效的lambda低 5-10%。

真的,我喜欢它的原因是因为我讨厌lambda因为人们在它是一个坏主意时过度使用它(例如,使用lambda map / filter总是比等效的 listcomp/genexpr 更冗长和更慢,但人们仍然继续这样做,没有可辨别的原因),即使在这种情况下它几乎不重要。


更新:从 3.8 开始,这种性能改进消失了,并且lambda更快(在 3.8 上使用lambda减少约 3% 的运行时间,在 3.9 上使用约 7%),对于使用ipython简单ipython 如果你想重现我的测试,我测试了:

>>> from collections import defaultdict
>>> %%timeit dd = defaultdict(lambda: defaultdict(list)); o = object
... dd[o()]

>>> %%timeit dd = defaultdict(defaultdict(list).copy); o = object
... dd[o()]

其中缓存o = object最大限度地减少了查找费用,并允许我们制作非常便宜、有保证的我们访问的唯一键(强制list自动激活),而无需做其他工作。

3.8 中的性能改进可能主要是由于LOAD_GLOBAL指令引入了每个操作码缓存,从而降低了从完整的dict查找中在lambda中查找defaultdictlist的成本(在list的情况下为两个,在内置程序中) ) 快速检查dict上的版本标签,然后从缓存中廉价加载,将成本降低约 40%。 3.9 改进可能(对此不确定)与 CPython 的内部结构更多地优化和支持 vectorcall 代码路径有关,以牺牲非 vectorcall 代码路径为代价( defaultdict(list).copy路径使用更多,相对而言) ,甚至在这些改进之前, defaultdict(list).copy也有一些lambda缺乏的低效率,为改进它提供了一些余地。

您可能必须这样做。

>>> from collections import defaultdict
>>> a=defaultdict()
>>> a["testkey"]=None
>>> a["testkey"]=defaultdict(list)
>>> a["testkey"]["list"]=["a","b","c"]
>>> a
defaultdict(None, {'testkey': defaultdict(<type 'list'>, {'list': ['a', 'b', 'c']})})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM