覆盖__add__方法后出现TypeError

时间:2011-02-22 18:25:01

标签: python

我想了解__add__的工作原理:

class MyNum:
    def __init__(self,num):
        self.num=num
    def __add__(self,other):
        return MyNum(self.num+other.num)
    def __str__(self):
        return str(self.num)

如果我把它们放在一个列表中

d=[MyNum(i) for i in range(10)]

这是有效的

t=MyNum(0)
for n in d:
    t=t+n
print t

但这不是:

print sum(d)
TypeError: unsupported operand type(s) for +: 'int' and 'instance'

我做错了什么?如何才能使 sum()起作用?

更新

我的问题是如何在支持__add__的对象列表中使用总和,需要尽可能保持通用。

5 个答案:

答案 0 :(得分:81)

您还需要定义__radd__以使其生效。

__radd__ 反向添加。当Python尝试评估x + y时,它首先尝试调用x.__add__(y)。如果此操作失败,则会回退到y.__radd__(x)

这允许您通过仅触摸一个类来覆盖添加。例如,考虑Python如何评估0 + x。尝试拨打0.__add__(x),但int对您的班级一无所知。您无法更改__add__中的int方法,因此需要__radd__。我想这是一种依赖倒置的形式。

正如Steven所指出的那样,sum在适当的位置运行,但从0开始。所以第一次添加是唯一需要使用__radd__的。作为一个很好的练习,你可以检查是否是这种情况!

答案 1 :(得分:16)

>>> help(sum)
Help on built-in function sum in module __builtin__:

sum(...)
    sum(sequence[, start]) -> value

    Returns the sum of a sequence of numbers (NOT strings) plus the value
    of parameter 'start' (which defaults to 0).  When the sequence is
    empty, returns start.

换句话说,提供一个起始值:

sum(d, MyNum(0))

从以下评论粘贴的编辑:

sum使用整数零的默认起始值​​。您编写的MyNum类不知道如何将自身添加到整数。要解决这个问题,您有两种选择。您可以为sum提供与您的类型相同的类型的起始值,也可以实现__radd__在添加不同类型的值时Python调用(例如当将d中的第一个值添加到默认起始值​​零时。

答案 2 :(得分:0)

class MyNum:
    def __init__(self,num):
        self.num=num
    def __add__(self,other):
        return self.num += other.num
    def __str__(self):
        return str(self.num)

one = MyNum(1)
two = MyNum(2)

one + two

print(two.num)

答案 3 :(得分:0)

另一个选项是reduce(Python 3.x中的functools.reduce)。

from functools import reduce
from operators import add
d=[MyNum(i) for i in range(10)]
my_sum = reduce(add,d)

答案 4 :(得分:0)

我反对使用起始点继续sum(),下面暴露的循环孔,

In [51]: x = sum(d, MyNum(2))

In [52]: x.num
Out[52]: 47

想知道为什么你在期待的时候得到47分 ...从MyNum()的第2个开始,先离开并将它们添加到结尾,所以预期结果= 44(总和(范围(2,10))

这里的事实是,2不是作为起始对象/位置保留,而是被视为对结果的补充

总和(范围(10))+ 2

哎呀,链接破了!!!!!!

使用 radd

下面是正确的代码。另请注意以下

只有在+右侧的对象是您的类实例时,Python才会调用__radd__     例如:2 + obj1

#!/usr/bin/env python

class MyNum:
    def __init__(self,num):
        self.num=num

    def __add__(self,other):
        return MyNum(self.num+other.num)

    def __radd__(self,other):
        return MyNum(self.num+other)

    def __str__(self):
        return str(self.num)

d=[MyNum(i) for i in range(10)]
print sum(d)    ## Prints 45
d=[MyNum(i) for i in range(2, 10)]
print sum(d)    ## Prints 44
print sum(d,MyNum(2))   ## Prints 46 - adding 2 to the last value (44+2)