繁体   English   中英

python collections.defaultdict分配但不查找

[英]python collections.defaultdict on assignment but not on lookup

我有以下代码:

from collections import *
nested_dict = lambda: defaultdict(nested_dict)
data = nested_dict()

这使我能够将字典中的任何新“路径”写成一行:

data['A']['B']['C']=3

这就是我想要的。 但是我想在运行时得到一个异常(对于任何不存在的路径):

var = data['A']['XXX']['C']

我觉得我在写作时需要defaultdict,在阅读时需要朴素的字典...

或者,是否有一种简单的好方法来检查defaultdict中是否存在``路径''而不修改其内容...

我尝试在查询之前将defaultdict转换回dict,希望:

dict(data)['A']['XXX']['C']

会引发异常...但是它一直在创建丢失的键...

一个明显的解决方案是仅将简单的dict与可以“具体化”中间键的函数一起使用:

def write_path(d, path, value):
    for key in path[:-1]:
        d = d.setdefault(key, {})
    d[path[-1]] = value

d = {}

write_path(d, ['a', 'b', 'c'], 3)
print(d)
print(d['a']['b']['c'])
print(d['a']['b']['d'])

输出

{'a': {'b': {'c': 3}}}
3
Traceback (most recent call last):
  File "writedefaultdict.py", line 11, in <module>
    print(d['a']['b']['d'])
KeyError: 'd'

您无法在查找和写入之间区分开来,因为查找是在data['A']['B']['C'] = 3分配中创建中介结构的。 在分配给'C'键之前,Python首先执行索引操作data['A'] ,然后首先执行['B'] __getitem____setitem____missing__参与,使这项工作挂钩没有给予足够的情况下访问之间进行区分,然后导致了'C'分配只从“阅读” 'XXX'在你的第二个例子。

您实际上只有3个选项:

  • 不要使用defaultdict 编写时,请使用dict.setdefault() 显式创建新的嵌套字典; 您可以根据需要链接这些调用:

     var = {} var.setdefault('A', {}).setdefault('B', {})['C'] = 3 

    或者您可以将递归行为包装在几个函数中

  • 创建defaultdict结构的递归副本,以在完成编写后将其替换为dict结构:

     def dd_to_d(dd): r = {} stack = [(r, dd)] while stack: target, dd = stack.pop() for key, value in dd.items(): if isinstance(value, defaultdict): sub = {} stack.append((sub, value)) value = sub target[key] = value return r var = dd_to_d(var) 
  • 将所有default_factory属性设置为None以禁用为丢失的键创建新值:

     def disable_dd(dd): stack = [dd] while stack: dd = stack.pop() dd.default_factory = None for key, value in dd.items(): if isinstance(value, defaultdict): stack.append(value) disable_dd(var) 

暂无
暂无

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

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