更新嵌套字典时的错误行为 python3
Erroneous behaviour while updating nested dictionary python3
在处理 python3.7 中收集包的 defaultdict class 时,我看到新键是从上一个键的副本生成的,而不是启动字典。有没有办法用给定的字典启动新元素,在下面的示例代码中是 init_dict
。
重现错误的示例代码:
from collections import defaultdict
init_dict = {'buy_qty': 0,
'sell_qty': 0}
pnl = defaultdict(lambda: init_dict)
pnl['a']['buy_qty'] += 1
pnl['a']['sell_qty'] += 1
现在我做的时候
pnl['b']
给我
{'buy_qty': 1, 'sell_qty': 1}
我正在寻找要用 init_dict
初始化的 pnl['b']
。我怎样才能做到这一点?
您的复制是参考,而不是价值。所以无论你对一本字典做什么,另一本都会受到影响。
您可以使用 id()
函数进行检查:
print(id(pnl['a']))
print(id(pnl['b']))
print(id(pnl['a']) == id(pnl['b']))
这将给出相同的内存地址:
1817103232768
1817103232768
True
验证它们是相同的对象。您可以通过使用 dict.copy()
分配字典的浅表副本来解决此问题,如评论中所述:
pnl = defaultdict(lambda: init_dict.copy())
或铸造dict()
:
pnl = defaultdict(lambda: dict(init_dict))
或使用 PEP 448 中的 **
-- 额外的解包概括
:
pnl = defaultdict(lambda: {**init_dict})
此外,考虑使用 collections.Counter
进行计数,而不是自己初始化零计数字典:
from collections import defaultdict, Counter
pnl = defaultdict(Counter)
pnl['a']['buy_qty'] += 1
pnl['a']['sell_qty'] += 1
print(pnl)
# defaultdict(<class 'collections.Counter'>, {'a': Counter({'buy_qty': 1, 'sell_qty': 1})})
print(pnl['b']['buy_qty'])
# 0
print(pnl['b']['buy_qty'])
# 0
pnl['b']['buy_qty'] += 1
pnl['b']['sell_qty'] += 1
print(pnl)
# defaultdict(<class 'collections.Counter'>, {'a': Counter({'buy_qty': 1, 'sell_qty': 1}), 'b': Counter({'buy_qty': 1, 'sell_qty': 1})})
Counter
是 dict
的子类,因此它们的工作方式与普通词典相同。
在处理 python3.7 中收集包的 defaultdict class 时,我看到新键是从上一个键的副本生成的,而不是启动字典。有没有办法用给定的字典启动新元素,在下面的示例代码中是 init_dict
。
重现错误的示例代码:
from collections import defaultdict
init_dict = {'buy_qty': 0,
'sell_qty': 0}
pnl = defaultdict(lambda: init_dict)
pnl['a']['buy_qty'] += 1
pnl['a']['sell_qty'] += 1
现在我做的时候
pnl['b']
给我
{'buy_qty': 1, 'sell_qty': 1}
我正在寻找要用 init_dict
初始化的 pnl['b']
。我怎样才能做到这一点?
您的复制是参考,而不是价值。所以无论你对一本字典做什么,另一本都会受到影响。
您可以使用 id()
函数进行检查:
print(id(pnl['a']))
print(id(pnl['b']))
print(id(pnl['a']) == id(pnl['b']))
这将给出相同的内存地址:
1817103232768
1817103232768
True
验证它们是相同的对象。您可以通过使用 dict.copy()
分配字典的浅表副本来解决此问题,如评论中所述:
pnl = defaultdict(lambda: init_dict.copy())
或铸造dict()
:
pnl = defaultdict(lambda: dict(init_dict))
或使用 PEP 448 中的 **
-- 额外的解包概括
:
pnl = defaultdict(lambda: {**init_dict})
此外,考虑使用 collections.Counter
进行计数,而不是自己初始化零计数字典:
from collections import defaultdict, Counter
pnl = defaultdict(Counter)
pnl['a']['buy_qty'] += 1
pnl['a']['sell_qty'] += 1
print(pnl)
# defaultdict(<class 'collections.Counter'>, {'a': Counter({'buy_qty': 1, 'sell_qty': 1})})
print(pnl['b']['buy_qty'])
# 0
print(pnl['b']['buy_qty'])
# 0
pnl['b']['buy_qty'] += 1
pnl['b']['sell_qty'] += 1
print(pnl)
# defaultdict(<class 'collections.Counter'>, {'a': Counter({'buy_qty': 1, 'sell_qty': 1}), 'b': Counter({'buy_qty': 1, 'sell_qty': 1})})
Counter
是 dict
的子类,因此它们的工作方式与普通词典相同。