Operator Overloading

Learn about the concept of operator overloading and how it is applied in Python using a practical example.

Overview

Python’s operators, +, /, -, *, and so on, are implemented by special methods on classes. We can apply Python operators more widely than the built-in numbers and collection types. Doing this can be called overloading the operators: letting them work with more than the built-in types.

Looking back at the the collections.abc module section, we dropped a hint about how Python connects some built-in features with our classes. When we look at the collections.abc.Collection class, it is the abstract base class for all Sized, Iterable, Containers; it requires three methods that enable two built-in functions and one built-in operator:

  • The __len__() method is used by the built-in len() function.

  • The __iter__() method is used by the built-in iter() function, which means it’s used by the for statement.

  • The __contains__() method is used by the built-in in operator. This operator is implemented by methods of built-in classes.

It’s not wrong to imagine the built-in len() function has this definition:

Press + to interact
def len(object: Sized) -> int:
return object.__len__()

When we ask for len(x), it’s doing the same thing as x.__len__(), but is shorter, easier to read, and easier to remember. Similarly, iter(y) is effectively y.__iter__(). And an expression like z in S is evaluated as if it was S.__contains__(z).

And yes, with a few exceptions, all of Python works this way. We write pleasant, easy-to-read expressions that are transformed into special methods. The only exceptions are the logic operations: and, or, not, and if-else. These don’t map directly to special method definitions.

Example

Because almost all of Python relies on special methods, it means we can change their behavior to add features. We can overload the operators with new data types. One prominent example of this is in the pathlib module:

Press + to interact
from pathlib import Path
home = Path.home()
print(home)
print(home/ "miniconda3"/ "envs")

What doesn’t vary is that the / operator is used to connect a Path object with string objects to create a new Path object.

Checks for operator overloading

The / operator is implemented by the __truediv__() and __rtruediv__() methods. Python has two places to look for an implementation to make operations commutative. Given an expression of A op B, where op is any of the Python operators like __add__ for +, Python does the following checks for special methods to implement the operator:

  1. There’s a special case when B is a proper subclass of A. In ...