It is possible to emulate container types, which support accessing values by key or index.
Consider this naive implementation of a sparse list, which stores only its non-zero elements to conserve memory.
Then, we can use a sparselist much like a regular list.
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.
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.
Magic (also called dunder as an abbreviation for double-underscore) methods in Python serve a similar purpose to operator overloading in other languages. They allow a class to define its behavior when it is used as an operand in unary or binary operator expressions. They also serve as implementations called by some built-in functions.
Consider this implementation of two-dimensional vectors.
Now it is possible to naturally use instances of the Vector class in various expressions.
Below are the operators that can be overloaded in classes, along with the method definitions that are required, and an example of the operator in use within an expression.
N.B. The use of other as a variable name is not mandatory, but is considered the norm.
a1 + a2
a1 - a2
a1 * a2
@ Matrix Multiplication
a1 @ a2 (Python 3.5)
a1 / a2 (Python 2 only)
a1 / a2 (Python 3)
// Floor Division
a1 // a2
a1 % a2
__pow__(self, other[, modulo])
a1 ** a2
<< Bitwise Left Shift
a1 << a2
>> Bitwise Right Shift
a1 >> a2
& Bitwise AND
a1 & a2
^ Bitwise XOR
a1 ^ a2
| (Bitwise OR)
a1 | a2
- Negation (Arithmetic)
~ Bitwise NOT
< Less than
a1 < a2
<= Less than or Equal to
a1 <= a2
== Equal to
a1 == a2
!= Not Equal to
a1 != a2
> Greater than
a1 > a2
>= Greater than or Equal to
a1 >= a2
[index] Index operator
in In operator
a2 in a1
(*args, ...) Calling
__call__(self, *args, **kwargs)
The optional parameter modulo for __pow__ is only used by the pow built-in function.
Each of the methods corresponding to a binary operator has a corresponding "right" method which start with __r, for example __radd__:
as well as a corresponding inplace version, starting with __i:
Since there's nothing special about these methods, many other parts of the language, parts of the standard library, and even third-party modules add magic methods on their own, like methods to cast an object to a type or checking properties of the object. For example, the builtin str() function calls the object's __str__ method, if it exists.
Some of these uses are listed below.
Casting to int
Casting to str
Casting to unicode
unicode(a1) (Python 2 only)
Casting to bool
There are also the special methods __enter__ and __exit__ for context managers, and many more.
This modified text is an extract of the original Stack Overflow Documentation created by following contributors and released under CC BY-SA 3.0