为什么我不能用__radd __替换__add__?

时间:2017-06-06 15:49:36

标签: python python-3.x

我(练习)试图创建一个使用罗马数字的课程。我试图将尽可能多的功能放入其中,因此我考虑让运营商对它们进行处理。我发现(例如,问题在其他方法对中持续存在)__add____radd__。文档说明如果__add__未定义(或者如果失败),则会查看__radd__,但当我尝试删除__add__并编辑__radd__方法时,它会正常工作在0 + myobject,但不在object1 + object2上。

以下是课程(因为它们对我的问题不重要,所以会删除一些内容):

class Roman:
    num_map = [('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)]

    def __init__(self, num=None):
        self.decimal = 0
        self.roman = 'N'
        if type(num) == type(0):
            self.__setattr__('decimal', num)
        elif type(num) == type(''):
            self.__setattr__('roman', num)


    def __setattr__(self, field, value):
        if field == 'decimal' and type(value) == type(0):
            super().__setattr__('decimal', value)
            super().__setattr__('roman', self.dec2roman(value))
        elif field == 'roman' and type(value) == type(''):
            super().__setattr__('roman', value)
            super().__setattr__('decimal', self.roman2dec(value))

方法self.dec2roman(integer)self.roman2dec(string)只是从一种格式转换为另一种格式。

现在,如果我尝试像这样__radd__

def __radd__(self, other):
    if other == 0:
        return self
    return Roman(self.decimal + other.decimal)

它不起作用,但这样做:

def __add__(self,other):
    return Roman(self.decimal + other.decimal)
def __radd__(self, other):
    if other == 0:
        return self
    return self + other

这是我得到的错误:

>>> from roman import Roman
>>> a = Roman(3)
>>> b = Roman('X')
>>> a + b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'Roman' and 'Roman'

有人知道发生了什么事吗?

2 个答案:

答案 0 :(得分:2)

根据Python文档的the “data model” section

  仅当左操作数不支持相应的操作并且操作数具有不同类型时,才会调用

[__radd__和类似函数]。

(强调补充。)这就是定义__radd__不适合你的原因:你试图添加相同类的两个项目。我不确定你为什么试图避免__add__,但这种方法显然是在这种情况下要求的。

答案 1 :(得分:1)

仅当您的对象是右手操作数时才调用__radd__()方法。您只需打印整数项的__doc__即可看到这一点:

In [4]: (1).__radd__.__doc__
Out[4]: 'Return value+self.'

您可以使用示例检查此行为:

In [7]: class A:
   ...:     def __radd__(self, other):
   ...:         return 10
   ...:     

In [8]: a = A()

In [9]: a + 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-429dec850246> in <module>()
----> 1 a + 2

TypeError: unsupported operand type(s) for +: 'A' and 'int'

In [10]: 2 + a
Out[10]: 10

但是当你使用其中两个对象时,python会调用第一个对象__add__方法,这就是它引发异常的原因。如果你想获得它,你可以简单地处理__add__方法中的问题,而不是为它编写逻辑代码。

例如,您可以使用other作为右手操作数,以便使用__radd__中的__add__

In [24]: class A:
             def __radd__(self, other):
                 return 10
             def __add__(self, other):
                 return 5 + other
   ....:     

In [25]: a = A()

In [26]: a + 2
Out[26]: 7

In [27]: 2 + a
Out[27]: 10

In [28]: a + a
Out[28]: 10