见下文,为什么+=
的实施会破坏原始计数器中的密钥?
>>> c = Counter({'a': 0, 'b': 0, 'c': 0})
>>> c.items()
[('a', 0), ('c', 0), ('b', 0)]
>>> c += Counter('abba')
>>> c.items()
[('a', 2), ('b', 2)]
我认为至少可以说这是不礼貌的,“X被计算0次”和“我们甚至没有计算Xs”之间存在很大差异。似乎collections.Counter
根本不是反制,它更像是一个多重集。
但是计数器是dict 的子类,我们允许用零值或负值构造它们:Counter(a=0, b=-1)
。如果它实际上是“一包东西”,这不会被禁止,限制init接受可迭代的可迭代物品吗?
为了进一步混淆问题,反对实施update
和subtract
方法,这些方法对+
和-
运算符有不同的行为。看来这堂课正在发生身份危机!
反击是一个字典还是一个包?
答案 0 :(得分:9)
Counter
是一种多重集合。来自Counter()
documentation:
提供了几种数学运算,用于组合
Counter
个对象以生成多重集合(计数大于零的计数器)。加法和减法通过添加或减去相应元素的计数来组合计数器。交点和并集返回相应计数的最小值和最大值。每个操作都可以接受带符号计数的输入,但输出将排除计数为零或更少的结果。
强调我的。
进一步说明,它会为您提供有关Counter
的多重性质的更多详细信息:
注意:计数器主要用于处理正整数以表示运行计数;但是,注意不要不必要地排除需要其他类型或负值的用例。为帮助处理这些用例,本节介绍了最小范围和类型限制。
[...]
- multiset方法仅适用于具有正值的用例。输入可以是负数或零,但仅创建具有正值的输出。没有类型限制,但值类型需要支持加法,减法和比较。
所以Counter
个对象 ;词典和行李。但是,标准词典不支持添加,但是Counter
会这样做,因此Counter
不会破坏字典设置的优先级。
如果您想保留零,请使用Counter.update()
并传入另一个对象的Counter.elements()
结果:
c.update(Counter('abba').elements())
演示:
>>> c = Counter({'a': 0, 'b': 0, 'c': 0})
>>> c.update(Counter('abba').elements())
>>> c
Counter({'a': 2, 'b': 2, 'c': 0})
答案 1 :(得分:8)
来自source;
def __add__(self, other):
'''Add counts from two counters.
>>> Counter('abbb') + Counter('bcc')
Counter({'b': 4, 'c': 2, 'a': 1})
'''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
newcount = count + other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count > 0:
result[elem] = count
return result
似乎Counter实现为删除键,其总和为零非正键。由于默认值为零,并且源也为零,因此生成的dict不包含该键。
也许你可以通过更新获得相同的行为:
a.update(b)
似乎做你想做的事。可能比较慢,__add__
方法的手工实现会快得多。