python Counter 是否预期表现如下?

Is python Counter expected to behave as follows?

我有一个字典列表如下

[
    {'sex': 2, 'newspaper_sheet__country': 'ML', 'n': 7},
    {'sex': 1, 'newspaper_sheet__country': 'ML', 'n': 5},
    {'sex': 2, 'newspaper_sheet__country': 'ML', 'n': 10}
]

然后我有 2 个计数器

from collections import Counter

counts = Counter()
counts1 = Counter()

我正在按以下格式更新两个计数器

for row in rows:
    counts.update({(row['sex'], row['newspaper_sheet__country']): row['n']})

counts1.update({(row['sex'], row['newspaper_sheet__country']): row['n'] for row in rows})

我希望 2 个计数的值相同,因为唯一的区别是 1 个使用 for 循环,另一个使用字典理解。

为什么这两个值不同?

通过在 for 循环的每次迭代中调用 Counter.updateCounter 对象将根据每次调用的输入字典进行更新。

通过字典理解,键值在传递给 Counter.update 之前首先聚合到字典中。由于字典理解中复制键的后面的值会覆盖相同键的前面的值,因此键 (2, 'ML') 的值 10 会覆盖相同键的值 7,从而导致Counter 对象最终没有考虑值 7

因为在这样的循环中调用 .update 并不等同于传递该字典理解的结果,请查看该字典理解创建的内容:

>>> rows = [
...     {'sex': 2, 'newspaper_sheet__country': 'ML', 'n': 7},
...     {'sex': 1, 'newspaper_sheet__country': 'ML', 'n': 5},
...     {'sex': 2, 'newspaper_sheet__country': 'ML', 'n': 10}
... ]
>>> {(row['sex'], row['newspaper_sheet__country']): row['n'] for row in rows}
{(2, 'ML'): 10, (1, 'ML'): 5}

字典有唯一的键,最后看到的条目被保留。

不同之处在于 update() 是通过列表推导完成的。

使用基于 for 循环的方法,计数器每次都会更新并聚合匹配键的计数,但是使用列表理解方法,它只会得到一个具有唯一键的字典。

列表理解方法可以分解为:

dic = {(row['sex'], row['newspaper_sheet__country']): row['n'] for row in rows}
print(dic)  # dic only contains unique key value pairs here
counts1.update(dic)

因此,counts1 仅更新一次,而 counts 由于基于循环的方法而更新多次。