[英]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
中查找defaultdict
和list
的成本(在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.