Python Language Overloading Handling unimplemented behaviour


If your class doesn't implement a specific overloaded operator for the argument types provided, it should return NotImplemented (note that this is a special constant, not the same as NotImplementedError). This will allow Python to fall back to trying other methods to make the operation work:

When NotImplemented is returned, the interpreter will then try the reflected operation on the other type, or some other fallback, depending on the operator. If all attempted operations return NotImplemented, the interpreter will raise an appropriate exception.

For example, given x + y, if x.__add__(y) returns unimplemented, y.__radd__(x) is attempted instead.

class NotAddable(object):

    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        return NotImplemented

class Addable(NotAddable):

    def __add__(self, other):
        return Addable(self.value + other.value)

    __radd__ = __add__

As this is the reflected method we have to implement __add__ and __radd__ to get the expected behaviour in all cases; fortunately, as they are both doing the same thing in this simple example, we can take a shortcut.

In use:

>>> x = NotAddable(1)
>>> y = Addable(2)
>>> x + x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NotAddable' and 'NotAddable'
>>> y + y
<so.Addable object at 0x1095974d0>
>>> z = x + y
>>> z
<so.Addable object at 0x109597510>
>>> z.value