 # Lesson 12 - Magic Methods in Python - Math methods

In the previous lesson, Magic Methods in Python, we introduced magic methods. In today's Python tutorial, we're going to continue with them. This time, we're going to show special methods for mathematical operators. We'll also show their use on the `Vector` class.

## Standard operators

These operators are called automatically on an object `a` when used like this:

`c = a + b`

The object `a` is passed through the `self` parameter and the object `b` is the `other` parameter.

The method is called on the first object when the `+` operator is used:

`c = a + b`

### __sub__(self, other)

The method is called when subtracting by the `-` operator:

`c = a - b`

### __mul__(self, other)

The method is called when multiplying by the `*` operator:

`c = a * b`

### __truediv__(self, other)

The method is called when dividing by the `/` operator:

`c = a / b`

### __floordiv__(self, other)

The method is called when dividing by the `//` operator (whole-number division):

`c = a // b`

### __mod__(self, other)

The method is called when getting the remainder after the whole-number division by using the modulo operator `%`:

`c = a % b`

### __divmod__(self, other)

Returns a pair `(a // b, a % b)` for integers:

`c = divmod(a, b)`

### __pow__(self, other, modulo)

The method is executed when we use the power `**` operator. The method should be able to take a third, optional (modulo) argument (https://docs.python.org/…nctions.html#pow):

`c = a ** b`

### __lshift__(self, other)

Executed when using the left bit-shift operator `<<`:

`c = a << b`

### __rshift__(self, other)

Executed when using the right bit-shift operator `>>`:

`c = a >> b`

### __and__(self, other)

Executed when using the bitwise AND operator `&`:

`c = a & b`

### __xor__(self, other)

Executed when using the bitwise XOR operator `^` (Non-Equivalence):

`c = a ^ b`

### __or__(self, other)

Executed when using the bitwise OR operator `|`:

`c = a | b`

## Reversed operators

Reversed operators are called on the second object when the first object doesn't implement the operator.

For example:

`sth = 1 + my_object`

If the `__add__()` magic method isn't supported by `int`, which is probably not, the `__radd__()` method is called on `my_object`.

These operators are called automatically on the object `b`, with object `b` being the `self` parameter and object `a` being the other parameter.

• `__radd__(self, other)` - Adding
• `__rsub__(self, other)` - Subtracting
• `__rmul__(self, other)` - Multiplying
• `__rtruediv__(self, other)` - True division
• `__rfloordiv__(self, other)` - Whole-number division
• `__rmod__(self, other)` - The remainder after whole-number division - modulo
• `__rdivmod__(self, other)` - Returns a pair `(a // b, a % b)` for integers
• `__rpow__(self, other, modulo)` - Power
• `__rlshift__(self, other)` - Left bit-shift
• `__rrshift__(self, other)` - Right bit-shift
• `__rand__(self, other)` - Bitwise AND
• `__rxor__(self, other)` - Bitwise XOR (Non-Equivalence)
• `__ror__(self, other)` - Bitwise OR

## In place operators

These operators allow us to use a shortened notation (in place). The parameters of the methods are `self` and `other`, but return a modified `self`. If there's no method, Python will try to emulate it using defined methods.

An example:

`my_object += 1`

Python calls the `__iadd__()` method. If it fails, it calls `__add__()` as follows:

```temp = my_object + 1 # calls __add__()
my_object = temp```
• `__iadd__(self, other)` - Adding
• `__isub__(self, other)` - Subtracting
• `__imul__(self, other)` - Multiplication
• `__itruediv__(self, other)` - True division
• `__ifloordiv__(self, other)` - Whole-number division
• `__imod__(self, other)` The remainder of whole-number division - modulo
• `__ipow__(self, other, modulo)` - Power
• `__ilshift__(self, other)` - Left bit-shift
• `__irshift__(self, other)` Right bit-shift
• `__iand__(self, other)` - Bitwise AND
• `__ixor__(self, other)` - Bitwise XOR (Non-Equivalence)
• `__ior__(self, other)` - Bitwise OR

## Other magic methods

Unary minus:

`-a`

Unary plus:

`+a`

### __abs__(self)

Absolute value implementing behavior for `abs()`:

`abs(a)`

Unary inversion:

`~a`

### __complex__(self)

Implements behavior for the `complex()` function:

`complex(a)`

### __int__(self)

Implements behavior for `int()`:

`int(a)`

### __float__(self)

Implements behavior for `float()`:

`float(a)`

### __round__(self, n)

Implements behavior for `round()`:

`round(a)`

### __index__(self)

Python uses this method to convert numeric types to `int`, for example, when truncating or using the built-in `bin()`, `hex()`, and `oct()` functions. This method should return the same result as the `__int__()` magic method. It should also return an integer (`int`).

## Method examples

Let's create a simple `Vector` class, holding its 2 `x` and `y` components. We'll implement some of the magic methods on it.

```class Vector:

def __init__(self, x, y):
self.x = float(x)
self.y = float(y)

def __str__(self):
return "({0.x}, {0.y})".format(self)

...```

The beginning is probably clear. In the `__str__()` method, we get the `x` and `y` attributes from `self`.

```def __add__(self, other):
if isinstance(other, Vector):
return Vector(self.x+other.x, self.y+other.y)
elif issubclass(type(other), Sequence):
if len(other) == 2:
return Vector(self.x+other, self.y+other)
raise NotImplemented```

First we compare whether the second object is also a `Vector`. If so, we return the sum of the `x` and `y` components as a new `Vector`.

Further branching is more complex. Using the built-in `issubclass()` function, we check if the second object class is a subclass of `Sequence` of the `collections.abc` module. This allows us to use the `len()` function on the object to get the first and second elements from the object. Without worrying that the object wouldn't support it. If both branches fail and don't return anything, the `NotImplemented` exception is thrown.

```def __mul__(self, other):
if issubclass(type(other), Real):
return Vector(self.x * other, self.y * other)
raise NotImplemented```

Here we check if `other` is a subclass of `Real` (real number) from the `numbers` module. Therefore, we can multiply the `Vector` by `int` or `float` and avoid unnecessary branching and checking of object types.

The classes in the `numbers` and `collections.abc` modules are actually abstract base classes. These are classes where we have to implement a certain object interface if we inherit them. But let's wait with this for the next lesson, Magic Methods in Python - Collections and Descriptors.

Application includes source codes in language Python

Article has been written for you by gcx11