避免在嵌套字典中存储值时出现键错误 (Python)
Avoiding key error storing values in nested dictionary (Python)
简介
以下字典具有三级键和一个值。
d = {
1:{
'A':{
'i': 100,
'ii': 200
},
'B':{
'i': 300
}
},
2:{
'A':{
'ii': 500
}
}
}
需要添加的示例。
d[1]['B']['ii'] = 600 # OK
d[2]['C']['iii'] = 700 # Keyerror on 'C'
d[3]['D']['iv'] = 800 # Keyerror on 3
问题陈述
我想创建代码来创建必要的嵌套键并避免任何键错误。
解决方案 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}}
似乎是合法的,但按顺序嵌入代码片段令人难以置信。我探索了 Whosebug 的其他解决方案,并阅读了 get() 和 setdefault() 函数。
解决方案 2
关于 get() 和 setdefault() 有很多 material 可以找到,但在嵌套字典上却没有那么多。最终我想出了:
def NewEntry_2(d, lv1, lv2, lv3, value):
return d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, value)
一行代码而已,没必要做成一个函数。可轻松修改以包含操作:
d[lv1][lv2][lv3] = d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, 0) + value
看起来很完美?
问题
当添加大量条目并进行大量修改时,选项2是否优于选项1?或者我应该定义函数 1 并调用它吗?我正在寻找的答案应该考虑到速度 and/or 潜在的错误。
例子
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}}}
更多背景
我是一名业务分析师,正在探索使用 Python 创建图形数据库,这将帮助我进行非常具体的分析。字典结构用于描述一个节点对其邻居之一的影响:
- lv1 是节点来自
- lv2 是
的节点
- lv3 是迭代
- 值为影响力(在
%)
在第一次迭代中,节点 1 直接影响节点 2。在第二次迭代中,节点 1 影响节点 2 影响的所有节点。
我知道可以帮助我的软件包 (networkx),但我想在开始使用它们之前先了解 Python/GraphDB。
关于嵌套字典,你应该看看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
更新: 创建深度嵌套 defaultdict
的一个有用技巧如下:
def tree():
return defaultdict(tree)
d = tree()
# now any depth is possible
# d[1][2][3][4][5][6][7][8] = 9
简介
以下字典具有三级键和一个值。
d = {
1:{
'A':{
'i': 100,
'ii': 200
},
'B':{
'i': 300
}
},
2:{
'A':{
'ii': 500
}
}
}
需要添加的示例。
d[1]['B']['ii'] = 600 # OK
d[2]['C']['iii'] = 700 # Keyerror on 'C'
d[3]['D']['iv'] = 800 # Keyerror on 3
问题陈述
我想创建代码来创建必要的嵌套键并避免任何键错误。
解决方案 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}}
似乎是合法的,但按顺序嵌入代码片段令人难以置信。我探索了 Whosebug 的其他解决方案,并阅读了 get() 和 setdefault() 函数。
解决方案 2
关于 get() 和 setdefault() 有很多 material 可以找到,但在嵌套字典上却没有那么多。最终我想出了:
def NewEntry_2(d, lv1, lv2, lv3, value):
return d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, value)
一行代码而已,没必要做成一个函数。可轻松修改以包含操作:
d[lv1][lv2][lv3] = d.setdefault(lv1, {}).setdefault(lv2,{}).setdefault(lv3, 0) + value
看起来很完美?
问题
当添加大量条目并进行大量修改时,选项2是否优于选项1?或者我应该定义函数 1 并调用它吗?我正在寻找的答案应该考虑到速度 and/or 潜在的错误。
例子
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}}}
更多背景
我是一名业务分析师,正在探索使用 Python 创建图形数据库,这将帮助我进行非常具体的分析。字典结构用于描述一个节点对其邻居之一的影响:
- lv1 是节点来自
- lv2 是 的节点
- lv3 是迭代
- 值为影响力(在 %)
在第一次迭代中,节点 1 直接影响节点 2。在第二次迭代中,节点 1 影响节点 2 影响的所有节点。
我知道可以帮助我的软件包 (networkx),但我想在开始使用它们之前先了解 Python/GraphDB。
关于嵌套字典,你应该看看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
更新: 创建深度嵌套 defaultdict
的一个有用技巧如下:
def tree():
return defaultdict(tree)
d = tree()
# now any depth is possible
# d[1][2][3][4][5][6][7][8] = 9