【问题标题】:is `__radd__` called if `__add__` raises `NotImplementedError`?如果`__add__`引发`NotImplementedError`,是否会调用`__radd__`?
【发布时间】:2019-11-13 00:08:19
【问题描述】:

假设我们写了一个小类:

class K:
    pass
obj = K()

是下面的代码吗……

total = 4 + obj

...和下​​面的基本一样?

import io
try:
    total = 4.__add__(obj)
except NotImplementedError:
    try:
        total = obj.__radd__(4)
    except AttributeError:
        # type(obj) does not have an `__radd__` method
        with io.StringIO() as string_stream:
            print(
                "unsupported operand type(s) for +:",
                repr(type(4).__name__),
                "and",
                repr(type(obj).__name__),
                file=string_stream
            ) # `repr` puts quotes around the type names
            msg = string_stream.getvalue()
        raise TypeError(msg) from None

【问题讨论】:

    标签: python python-3.x operator-overloading


    【解决方案1】:

    触发__radd__()的行为其实不是NotImplementedError,而是一个叫做NotImplemented的特殊对象:

    >>> help(NotImplemented)
    Help on NotImplementedType object:
    
    class NotImplementedType(object)
     |  Methods defined here:
     |  
     |  __reduce__(...)
     |      Helper for pickle.
     |  
     |  __repr__(self, /)
     |      Return repr(self).
     |  
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |  
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
    

    NotImplementedError 仍会作为错误传播。但是,返回NotImplemented 对象(而不是引发错误)将允许__radd__() 触发:

    >>> class A:
    ...     def __add__(self, other):
    ...         raise NotImplementedError()
    ... 
    >>> class B:
    ...     def __add__(self, other):
    ...         print("__add__ was called")
    ...     def __radd__(self, other):
    ...         print("__radd__ was called")
    ... 
    >>> class C:
    ...     def __add__(self, other):
    ...         return NotImplemented
    ... 
    >>> a, b, c = A(), B(), C()
    >>> b + a
    __add__ was called
    >>> a + b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in __add__
    NotImplementedError
    >>> b + c
    __add__ was called
    >>> c + b
    __radd__ was called
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2021-10-22
      • 2020-07-12
      • 2012-01-23
      • 1970-01-01
      • 2010-10-27
      相关资源
      最近更新 更多