定义__radd__时抑制__add__

时间:2017-07-24 20:01:08

标签: python

我有两个课程FooBar

class Foo(str):
    def __add__(self, other):
        return 'Foo.__add__ called'


class Bar(str):
    def __radd__(self, other):
        return 'Bar.__radd__ called'

如您所见,我Foo实施__add__Bar实施__radd__

我可以创建这些类的对象并添加它们,因为定义了魔术方法。

f = Foo('foo')
b = Bar('bar')

但是,添加它们会产生以下结果:

In [390]: f + b
Out[390]: 'Foo.__add__ called'

如何设置它以便Bar.__radd__方法优先于Foo.__add__调用?

3 个答案:

答案 0 :(得分:2)

引用docs关于__rstuff__方法的信息:

  

如果左操作数不支持相应的操作且操作数的类型不同,则这些函数仅称为。例如,要评估表达式x - y,其中y是具有__rsub__()方法的类的实例,如果y.__rsub__(x)返回x.__sub__(y),则会调用NotImplemented

因此,在您的情况下,左侧操作数Foo确实具有__add__方法,因此,它会立即被调用。为避免这种情况,如果另一个参数的类型为return NotImplemented,则Foo.__add__可以Bar

答案 1 :(得分:1)

有两种方法可以做到这一点。

  1. 在与Foo相关的Bar中添加明确的签到。
  2. class Foo(str):
        def __add__(self, other):
            if isinstance(other, Bar):
                return NotImplemented
            return 'Foo.__add__ called'
    
    
    class Bar(str):
        def __radd__(self, other):
            return 'Bar.__radd__ called'
    
    1. 使Bar成为Foo
    2. 的子类

      From docs:

        

      注意:如果右操作数的类型是左操作数的子类   type和该子类提供了反射的方法   操作,此方法将在左操作数之前调用   非反射方法。此行为允许子类重写   他们的祖先的行动。

答案 2 :(得分:1)

正如Datamodel部分中的Python参考文档中所解释的那样,Python使用该命令来解决这种情况:

  1. 检查第一个操作数上的__add__
  2. 并且只有在未实施时才检查第二个__radd__
  3. 如果__add__实施other方法,则可以检查您的__radd__实施方案,以解决您的问题(不是非常漂亮/ pythonic)。

    例如:

    class Foo(str):
        def __add__(self, other):
            try:
                return other.__radd__(self)
            except NotImplemented:
                pass
            # __radd__ not implement so return __add__ behavior 
            return 'Foo.__add__ called'
    

    结果:

    In [5]: f + b
    Out[5]: 'Bar.__radd__ called'