python collections.defaultdict分配但不查找

时间:2019-01-08 17:57:00

标签: python data-structures

我有以下代码:

ProjectTo

这使我能够在字典中写任何新的“路径”作为一个衬里:

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

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

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

我觉得我在写作时需要defaultdict,在阅读时需要普通字典...

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

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

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

会引发异常...但是它会不断创建丢失的键...

2 个答案:

答案 0 :(得分:1)

一个明显的解决方案是只使用简单的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'

答案 1 :(得分:1)

您无法在查找和写入之间区分开来,因为查找会在data['A']['B']['C'] = 3分配中创建您的中介结构。在分配给data['A']键之前,Python首先执行索引操作['B'],然后先执行'C'。没有为完成该工作所涉及的__getitem____setitem____missing__钩子提供足够的上下文来区分访问之间的区别,从而导致访问'C'仅从“读取” { {1}}在第二个示例中。

您这里实际上只有3个选择:

  • 请勿使用'XXX'。写作时,明确地使用dict.setdefault()创建新的嵌套字典;您可以根据需要链接这些呼叫:

    defaultdict

    或者您可以wrap recursive behaviour in a few functions

  • 创建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