避免在嵌套字典中存储值的关键错误 (Python)

1 python dictionary nested graph setdefault

介绍

以下字典具有三个级别的键,然后是一个值。

d = {
    1:{
        'A':{
            'i': 100,
            'ii': 200
            }, 
        'B':{
            'i': 300
            }
        }, 
    2:{
        'A':{
            'ii': 500
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

需要补充的例子。

d[1]['B']['ii'] = 600      # OK
d[2]['C']['iii'] = 700     # Keyerror on 'C'
d[3]['D']['iv'] = 800      # Keyerror on 3
Run Code Online (Sandbox Code Playgroud)

问题陈述

我想创建能够创建必要的嵌套键并避免任何键错误的代码。

解决方案1

我想出的第一个解决方案是:

def NewEntry_1(d, lv1, lv2, lv3, value):
    if lv1 in d:
        if lv2 in d:
            d[lv1][lv2][lv3] = value
        else:
            d[lv1][lv2] = {lv3: value}
    else:
        d[lv1] = {lv2: {lv3: value}}
Run Code Online (Sandbox Code Playgroud)

看起来是合法的,但是按照代码段的顺序嵌入它让它变得令人难以置信。我探索了 Stackoverflow 的其他解决方案,并阅读了 get() 和 setdefault() 函数。

解决方案2

有很多关于 get() 和 setdefault() 的资料可以找到,但关于嵌套字典的资料不多。最终我能够想出:

def NewEntry_2(d, lv1, lv2, lv3, value):
    return d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, value)
Run Code Online (Sandbox Code Playgroud)

这是一行代码,因此实际上没有必要将其设为函数。易于修改以包括操作:

d[lv1][lv2][lv3] = d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, 0) + value
Run Code Online (Sandbox Code Playgroud)

看起来很完美?

添加大量条目并进行多次修改时,选项2是否比选项1更好?或者我应该定义函数 1 并调用它?我正在寻找的答案应该考虑速度和/或错误的可能性。

例子

NewEntry_1(d, 1, 'B', 'ii', 600)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}}}

NewEntry_1(d, 2, 'C', 'iii', 700)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}, 'C': {'iii': 700}}}

NewEntry_1(d, 3, 'D', 'iv', 800)
# output = {1: {'A': {'i': 100, 'ii': 200}, 'B': {'i': 300, 'ii': 600}}, 2: {'A': {'ii': 500}, 'C': {'iii': 700}}, 3: {'D': {'iv': 800}}}
Run Code Online (Sandbox Code Playgroud)

更多背景

我是一名业务分析师,正在探索使用 Python 来创建图形数据库,这将帮助我进行非常具体的分析。字典结构用于描述一个节点对其邻居之一的影响:

  • lv1 是节点来自
  • lv2 是节点到
  • lv3 是迭代
  • 值是影响(%)

在第一次迭代中,节点 1 对节点 2 有直接影响。在第二次迭代中,节点 1 影响节点 2 影响的所有节点。

我知道可以帮助我使用它的软件包 (networkx),但在我想开始使用它们之前,我试图了解 Python/GraphDB。

sch*_*ggl 5

至于嵌套字典,你应该看看defaultdict. 使用它可以为您节省大量的函数调用开销。嵌套defaultdict构造lambda对其默认工厂采用函数:

d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))  # new, shiny, empty
d[1]['B']['ii'] = 600      # OK
d[2]['C']['iii'] = 700     # OK
d[3]['D']['iv'] = 800      # OK
Run Code Online (Sandbox Code Playgroud)

更新:创建深度嵌套的有用技巧defaultdict如下:

def tree():
    return defaultdict(tree)

d = tree()  
# now any depth is possible
# d[1][2][3][4][5][6][7][8] = 9
Run Code Online (Sandbox Code Playgroud)