为什么一个可以加到自身的类不能求和?(a+a 有效, sum([a,a]) 失败)

Jan*_*ano 2 python

在以下代码段中,我创建了一个 Counter 对象,并尝试使用三种方式将其添加到自身中。使用“+”的标准加法,从列表中减少(内部与前面相同)并使用列表中的函数 sum()。

前 2 个工作并返回预期结果,但第三个引发 TypeError 异常。

从这里我有两个问题:

  1. 如果加法有效, sum() 失败的原因是什么?
  2. 当我用 + 添加到对象时,会使用类的 __ add__ 方法。调用 sum() 时使用什么方法(如果有)?

Counter 只是一个例子,当我创建新类时,我对一般情况感兴趣,而不是对这个特别感兴趣。

from collections import Counter
from functools import reduce
a = Counter([1,1,1,1])

print(a+a+a)
print(reduce(lambda x, y: x + y, [a,a, a]))
sum([a, a, a])
Run Code Online (Sandbox Code Playgroud)

印刷:

Counter({1: 12})
Counter({1: 12})
Traceback (most recent call last):
  File "/home/user/.PyCharmCE2019.3/config/scratches/scratch.py", line 20, in <module>
    print(sum([a, a,]))
TypeError: unsupported operand type(s) for +: 'int' and 'Counter'
Run Code Online (Sandbox Code Playgroud)

kay*_*ya3 8

这是因为sum([a, a])不是在做a + a;它实际上是在做0 + a + a。在Counter类的实例可以被添加到的实例Counter,但它们不能被添加到整数0

想想你会如何自己编写sum函数:

def sum(lst):
    total = 0
    for x in lst:
        total += x
    return total
Run Code Online (Sandbox Code Playgroud)

原则上,您可以初始化total = lst[0]然后迭代lst[1:]以添加剩余的值。问题是,你不能得到一个空序列的总和。所以Python的实际sum功能就像上面的代码,只不过你可以指定起始值(docs link),所以它实际上更像这样:

def sum(lst, start=0):
    total = start
    for x in lst:
        total = total + x
    return total
Run Code Online (Sandbox Code Playgroud)

这意味着对于您想要的行为,您可以执行sum([a, a], Counter()),因为“空”Counter0添加数字的作用相同。

请注意,它是 liketotal = total + x和 not total += x,因为它们对于像list. 在一般情况下,您的类需要一个附加标识作为sum;的起始值。如果“身份”没有合适的值,则应reduce改用。