Search code examples
pythonclassnumbersabstract-base-class

Why are __sub__ and __rsub__ implemented and, in this way, for numbers.Complex


I was looking at the implementation of Complex in the numbers module and noticed __sub__ and __rsub__s implementation that looked like this:

def __sub__(self, other):
    """ self - other """
    return self + -other

def __rsub__(self, other):
    """ other - self """
    return -self + other

This confused me.

Firstly, I'm not really sure why these were implemented (guessing all subclasses of Complex can fall-back to it?) and, secondly, I can't understand why they chose to use the unary - like this for its implementation.

Any ideas?


Solution

  • This is a generic implementation that subclasses can use, yes, if they so desire. This is an additional goal; the primary goal of these ABC types is to be able to duck-type numeric types (see PEP 3141 – A Type Hierarchy for Numbers.

    The implementation uses unary minus to avoid recursion; if you used self - other then Python uses self.__sub__(other) or self.__rsub__(other) again.

    Because subtraction can be cast as addition with a unary minus operation, the authors of the ABC were able to provide you these methods as a bonus; the alternative would be to provide @abstracmethod methods instead, forcing subclasses to provide a concrete implementation. Your subclass can now, optionally, implement those methods in a different way if that is more efficient, but they don't have to.

    This is a pattern used in all ABCs the standard library provides. If you take a look at the documentation for the collections.abc module you'll notice a Mixin Methods column; these are all methods the respective ABC has provided as concrete implementations that may or may not rely on the abstract methods defined by that ABC or its base classes.

    Also see the general PEP 3119 – Introducing Abstract Base Classes upon which PEP 3141 is built:

    Some ABCs also provide concrete (i.e. non-abstract) methods; for example, the Iterator class has an __iter__ method returning itself, fulfilling an important invariant of iterators (which in Python 2 has to be implemented anew by each iterator class). These ABCs can be considered "mix-in" classes.