更新嵌套字典python3

时间:2020-05-22 08:56:51

标签: python-3.x dictionary defaultdict

在python3.7中处理集合包的defaultdict类时,我看到新密钥是从最后一个密钥的重复生成的,而不是启动字典。有没有一种方法可以使用给定的字典(在下面的示例代码中为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}

我正在寻找pnl['b']要初始化的init_dict。我该如何实现?

1 个答案:

答案 0 :(得分:2)

您通过引用而不是按值进行复制。因此,无论您对一本字典做什么,另一本字典都会受到影响。

您可以使用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 -- Additional Unpacking Generalizations 中的**

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})})

Counterdict的子类,因此它们的作用与普通词典相同。