In Python, there are 7 arithmetic operators you can use to perform basic mathematical operations.

Here is a table of all the arithmetic operators in Python with examples:

Operator | Name | Use |
---|---|---|

+ | Addition | x + y |

– | Subtraction | x – y |

* | Multiplication | x * y |

/ | Division | x / y |

% | Modulus | x % y |

** | Exponentiation | x ** y |

// | Floor division | x // y |

This table is a quick cheat sheet.

However, there are so many things you can do with arithmetic operators in Python. In this guide, you are going to learn how to use arithmetic operators extensively.

Before we start, let’s quickly learn what arithmetic precedence and precedence groups mean:

## Precedence Groups

When there are multiple arithmetic operations chained together, the Python compiler needs to know which ones to evaluate first.

1 + 2 * 3 ** 4 / 5

This is where **precedence** is used.

The precedence group of the arithmetic operator specifies in which order expressions are evaluated.

Here is the precedence grouping of the arithmetic operators in Python. The upper the operator is on the table, the higher the precedence.

Operators | Meaning |
---|---|

`()` | Parentheses |

`**` | Exponent |

`*` , `/` , `//` , `%` | Multiplication, Division, Floor division, Modulus |

`+` , `-` | Addition, Subtraction |

Now that you understand what is precedence, it is time to jump into the arithmetic operators in Python.

## Addition

In Python, you can add two numeric values together using the addition operator (+).

x + y

For example:

>>> 1 + 2 3

### The += Operator

When adding variables, you can combine the addition operator (+) with the assignment operator (=) to form the addition assignment operator (+=).

x += y

This is a shorthand for:

x = x + y

For example:

>>> a = 1 >>> a += 10 >>> a 11

### Precedence

The addition operator (+) belongs to the lowest precedence group with subtraction.

This means any other arithmetic operations are carried out first.

For example:

>>> 1 + 2 * 3 7

Here 2 * 3 is calculated before adding it to 1.

In other words, the Python compiler sees the above expression as:

1 + (2 * 3)

Where any expressions inside the parenthesis are calculated first.

Now you understand the basics of the addition operator in Python.

Next, let’s take a look at the more advanced use of addition.

### The __add__() Method

In Python, you can add numeric types together to produce a new numeric value that represents the sum of the two.

This is made possible by the **__add__()** method that is implemented behind the scenes.

As a matter of fact, whenever you use the + operator, you are actually calling the **__add__()** method of the object.

You can verify that this is the case by running a simple experiment:

>>> 1 + 2 3 >>> (1).__add__(2) 3

Understanding this is useful in a moment.

In Python, you can create a custom type by implementing a class that specifies the type.

For example, let’s create a **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos

Now, let’s see what happens when you try to add two **Weight** objects together:

w1 = Weight(50) w2 = Weight(150) tot = w1 + w2 print(tot.kilos)

This results in an error:

TypeError: unsupported operand type(s) for +: 'Weight' and 'Weight'

The error says you cannot use + on two **Weight** objects.

This is not a surprise.

How could the Python interpreter even know what it means to add two weights together?

But there is a way for you to make this work.

To support addition with custom types in Python, implement the **__add__()** method into the custom class.

For instance, let’s make it possible to add **Weight** objects together by summing the **kilos** of the objects:

class Weight: def __init__(self, kilos): self.kilos = kilos def __add__(self, otherWeight): return Weight(self.kilos + otherWeight.kilos)

The **__add__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It then sums up the **kilos** of the weights, creates a new **Weight** object, and returns it.

Now you can add two **Weight** objects together to create larger **Weight** objects, for example:

w1 = Weight(50) w2 = Weight(150) tot = w1 + w2 print(tot.kilos)

Output:

200

Pretty handy, isn’t it?

Now you understand how to add two custom objects together in Python using the **__add__** method.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Adding Different Types

Let’s try to add a **Weight** object and an **int**:

w1 = Weight(50) tot = w1 + 150 print(tot.kilos)

This results in the following error:

AttributeError: 'int' object has no attribute 'kilos'

This is because we have not specified what happens when adding a **Weight** to another object, such as to an **int**.

To support adding different types, you need to extend the implementation of the **__add__()** method:

- If the right-hand side is an
**int**, we can directly add it to the**kilos**of the**Weight**object. - If the right-hand side is not an
**int**, we assume it is a**Weight**. Thus, we need to access the**kilos**before adding them to the left-hand side.

Here is what the updated class looks like:

class Weight: def __init__(self, kilos): self.kilos = kilos def __add__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos + otherWeight) else: return Weight(self.kilos + otherWeight.kilos)

Now you can add **Weight** objects and **ints** together:

w1 = Weight(100) total = w1 + 200 print(total.kilos)

Output:

300

But there is a small problem.

When you reverse the order of the addition:

w1 = Weight(100) total = 200 + w1 print(total.kilos)

There is an error, even though one would expect it to work:

TypeError: unsupported operand type(s) for +: 'int' and 'Weight'

Now, let’s think about why this happens.

As you now know, calling **a + b** is the same as calling **a.__add__(b)**.

In the failing piece of code, you are calling **200 + w1**, that is, **(200).__add__(w1)**.

Now, this is problematic.

Trying to add a **Weight** object to an** int** object does not work because **int** has no idea about our **Weight** class. That is to say that the **__add__** method in the **int** class does not handle adding **Weight** objects.

To overcome this, you would need to modify the native implementation of the **int** type.

But this is a no-go.

Instead, Python has a built-in **__radd__()** method you can use to swap the order of the addition.

#### The __radd__() Method

The **__radd__()** method stands for “right addition”.

The idea is simple:

- If
**a + b**fails, call**b.__radd__(a)**which is implemented such that**a + b**does not cause problems.

Let’s implement the **__radd__()** method to the **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __add__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos + otherWeight) else: return Weight(self.kilos + otherWeight.kilos) def __radd__(self, kilos_int): return Weight(kilos_int + self.kilos)

Now you check that it works:

w1 = Weight(50) total = 150 + w1 print(total.kilos)

Output:

200

Awesome.

Now that you understand how addition works in Python, let’s move on to subtraction.

## Subtraction

In Python, you can subtract two numeric values from one another by using the subtraction operator (-).

x - y

For example:

>>> 1 - 2 -1

### The -= Operator

When decrementing variables, you can combine the subtraction operator (-) with the assignment operator (=) to form the subtraction assignment operator (-=).

x -= y

This is a shorthand for:

x = x - y

For example:

>>> a = 1 >>> a -= 10 >>> a -9

### Precedence

The subtraction operator belongs to the lowest precedence group with addition.

This means any other arithmetic operations are calculated first.

For example:

>>> 1 - 2 * 3 -5

Here 2 * 3 is calculated before subtracting it from 1.

In other words, the Python compiler sees the above expression as:

1 - (2 * 3)

Let’s have a look at some advanced use of the subtraction operator.

### The __sub__() Method

In Python, you can subtract two numeric types from one another to produce a new value that represents the difference between the two.

This is made possible by the **__sub__()** method behind the scenes.

The working principle is exactly the same as the **__add__()** method from the previous section.

Whenever you use the – operator, you are actually calling the **__sub__()** method.

>>> 1 - 2 -1 >>> (1).__sub__(2) -1

In Python, you can create a custom type by implementing a class that specifies the type.

For example, let’s continue with the **Weight** class implemented in the previous chapter:

class Weight: def __init__(self, kilos): self.kilos = kilos

Now, let’s see what happens when you try to subtract two **Weight** objects:

w1 = Weight(50) w2 = Weight(150) diff = w1 - w2 print(diff.kilos)

This results in the following error:

TypeError: unsupported operand type(s) for -: 'Weight' and 'Weight'

The error says you cannot use – on two **Weight** objects.

However, there is a way for you to make this work.

To support subtraction with custom types, implement the **__sub__()** method into the custom class.

For instance, let’s make it possible to subtract **Weight** objects from one another by subtracting the **kilos** of the objects:

class Weight: def __init__(self, kilos): self.kilos = kilos def __sub__(self, otherWeight): return Weight(self.kilos - otherWeight.kilos)

The **__sub__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It subtracts the kilos of the weights, creates a new **Weight** object, and returns it.

Now you can subtract two **Weight** objects to get the weight difference as a new **Weight** object:

w1 = Weight(50) w2 = Weight(150) diff = w1 - w2 print(diff.kilos)

Output:

-100

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Subtracting Different Types

Let’s try to subtract an **int** from a **Weight**:

w1 = Weight(50) diff = w1 - 150 print(diff.kilos)

This throws an error:

AttributeError: 'int' object has no attribute 'kilos'

We have not specified what happens when subtracting something else than a **Weight** from a **Weight** object. This is why the above piece of code does not work.

To make subtracting different types work, extend the implementation of the **__sub__()** method:

- If the right-hand side is an
**int**, we can directly subtract it from the**kilos**. - If the right-hand side is not an
**int**, we assume it is a**Weight**. Thus, we need to access the**kilos**before subtracting.

class Weight: def __init__(self, kilos): self.kilos = kilos def __sub__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos - otherWeight) else: return Weight(self.kilos - otherWeight.kilos)

Now it works:

w1 = Weight(50) diff = w1 - 150 print(diff.kilos)

Output:

-100

But there is one more problem.

When you reverse the order of the subtraction:

w1 = Weight(50) diff = 150 - w1 print(diff.kilos)

There is an error, even though one would expect it to work:

TypeError: unsupported operand type(s) for -: 'int' and 'Weight'

As you now know, calling **a – b** is the same as calling **a.__sub__(b)**.

In the above you are calling **150 – w1**, that is, **(150).__sub__(w1)**.

This is the problem.

Trying to subtract a **Weight** object from an** int** object does not work because the built-in **int** type has no idea about the **Weight** class.

To overcome the issue, you would need to modify the native implementation of the **int** type.

But there is a better way to do it.

Instead, Python has a built-in **__rsub__()** method you can use to swap the order of the subtraction.

#### The __rsub__() Method

The **__rsub__()** method stands for “right subtraction”.

The idea of this is easy to understand:

- If
**a – b**fails, call**b.__rsub__(a)**which is implemented such that**a – b**does not cause problems.

Let’s implement the **__rsub__()** method to the **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __sub__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos - otherWeight) else: return Weight(self.kilos - otherWeight.kilos) def __rsub__(self, kilos_int): return Weight(kilos_int - self.kilos)

For example:

w1 = Weight(50) diff = 150 - w1 print(diff.kilos)

Output:

100

Now you understand how subtraction works in Python.

Also, you may have noticed there is a clear pattern between each arithmetic operator. Each arithmetic operator corresponds to a special method with a double underscore method that is called behind the scenes. This method can be customized for a custom type.

Anyway, let’s continue with multiplication.

## Multiplication

In Python, you can multiply two numeric types by using the multiplication operator (*).

x * y

For example:

>>> 3 * 2 6

### The *= Operator

When multiplying variables, you may combine the multiplication operator (*) with the assignment operator (=) to form the multiplication assignment operator (*=).

x *= y

This is a shorthand for:

x = x * y

For example:

>>> a = 2 >>> a *= 10 >>> a 20

### Precedence

The multiplication operator belongs to a higher precedence group than addition and subtraction.

This means multiplication takes place before addition or subtraction.

For example:

>>> 1 + 2 * 3 7

Here 2 * 3 is calculated before adding it to 1.

Here is how you can group the operations in your mind:

1 + (2 * 3)

Where expressions inside the parenthesis are calculated first.

Next, let’s take a look at the more advanced use of multiplication.

### The __mul__() Method

In Python, you can multiply numeric types to produce a new value that represents the product of the two. This is made possible by the **__mul__()** method that is implemented behind the scenes.

As a matter of fact, whenever you use the * operator, you are actually calling the **__mul__()** method behind the scenes.

You can try it to see how it works:

>>> 3 * 2 6 >>> (3).__mul__(2) 6

In Python, you can create a custom type by implementing a class that specifies the type.

For example, let’s create a **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos

Now, let’s see what happens when you try to multiply two **Weight** objects:

w1 = Weight(50) w2 = Weight(150) prod = w1 * w2 print(prod.kilos)

This results in the following error:

TypeError: unsupported operand type(s) for *: 'Weight' and 'Weight'

The error says you cannot use * on two **Weight** objects.

This is not a surprise.

How could the Python interpreter even know what it means to multiply two weights?

Anyway, similar to the other arithmetic operators, there is a way to make this work.

To support multiplication with custom types in Python, implement the **__mul__()** method into the custom class.

For instance, let’s make it possible to multiply **Weight** objects by multiplying the **kilos** of the objects:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mul__(self, otherWeight): return Weight(self.kilos * otherWeight.kilos)

The **__mul__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It then multiplies the **kilos** of the weights, creates a new **Weight** object, and returns it.

Let’s make sure it works:

w1 = Weight(50) w2 = Weight(150) prod = w1 * w2 print(prod.kilos)

Output:

7500

Amazing!

Now you understand how to multiply custom types by one another.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Multiplying Different Types

Let’s try to multiply a **Weight** object by an **int**:

w1 = Weight(50) prod = w1 * 150 print(prod.kilos)

This results in the following error:

AttributeError: 'int' object has no attribute 'kilos'

This happens because it is not specified what happens when multiplying a **Weight** by another object.

To make multiplying different types work, extend the implementation of the **__mul__()** method:

- If the right-hand side is an
**int**, we can directly multiply it by the kilos of the weight. - If the right-hand side is not an
**int**, we assume it is a**Weight**. So we need to access the**kilos**before the multiplication.

Here is the updated class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mul__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos * otherWeight) else: return Weight(self.kilos * otherWeight.kilos)

Now multiplying **Weights** by **ints** is possible:

w1 = Weight(50) prod = w1 * 150 print(prod.kilos)

Output:

7500

Now there is one more issue.

If you reverse the order of the multiplication:

w1 = Weight(50) prod = 150 * w1 print(prod.kilos)

There is an error, even though one would expect it to work:

TypeError: unsupported operand type(s) for *: 'int' and 'Weight'

Let’s see why this error happens.

Calling **a * b** is the same as calling **a.__mul__(b)**.

Above you are calling **150 * w1**, that is, **(150).__mul__(w1)**.

This is the problem.

Trying to multiply an **int** object by a** Weight** does not work because the built-in **int** type has no idea about the **Weight** class.

To overcome the issue, you would need to make changes to the native implementation of the **int** type.

Instead of doing this, Python has a built-in **__rmul__()** method you can safely implement to swap the order of the multiplication.

#### The __rmul__() Method

The **__rmul__()** method stands for “right multiplication”.

The working principle is simple:

- If
**a * b**fails, call**b.__rmul__(a)**which is implemented such that**a * b**does not cause problems.

Let’s implement the **__rmul__()** method to the **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mul__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos * otherWeight) else: return Weight(self.kilos * otherWeight.kilos) def __rmul__(self, kilos_int): return Weight(self.kilos * kilos_int)

Now it works:

w1 = Weight(50) prod = 150 * w1 print(prod.kilos)

Output:

7500

Cool!

Next, let’s take a look at division.

## Division

In Python, you can divide two numeric types using the division operator (/).

x / y

For example:

>>> 3 / 2 1.5

### The /= Operator

When you want to update a variable by dividing it, you can combine the division operator (/) with the assignment operator (=) to form the division assignment operator (/=).

x /= y

This is a shorthand for:

x = x / y

For example:

>>> a = 2 >>> a /= 10 >>> a 0.2

### Precedence

Division operation precedes addition and subtraction.

For example:

>>> 1 + 6 / 3 3

Here 6 / 3 is calculated before adding it to 1.

Here is how you can group the operations in your mind:

1 + (6 / 3)

Where expressions inside the parenthesis are calculated first.

Next, let’s take a look at the more advanced use of division.

### The __truediv__() Method

In Python, you can divide numeric types to produce a new value that represents the division of the two.

This is made possible by the **__truediv__()** method that is implemented behind the scenes.

Whenever you use the / operator, you are actually calling the **__truediv__()** method under the hood.

You can verify this by running a simple test:

>>> 3 / 2 1.5 >>> (3).__truediv__(2) 1.5

In Python, you can create a custom type by implementing a class.

For example, let’s use the **Weight** class from earlier examples:

class Weight: def __init__(self, kilos): self.kilos = kilos

Now, let’s divide two **Weight** objects:

w1 = Weight(50) w2 = Weight(150) res = w1 / w2 print(res.kilos)

This results in an error:

TypeError: unsupported operand type(s) for /: 'Weight' and 'Weight'

You cannot use / on two **Weight** objects. This is because the Python interpreter has no idea what division means in the context of **Weight**.

Anyway, you can change this.

To support the division of custom types in Python, implement the **__truediv__()** method into the custom class.

For instance, let’s make it possible to divide **Weight** objects by dividing the **kilos** properties:

class Weight: def __init__(self, kilos): self.kilos = kilos def __truediv__(self, otherWeight): return Weight(self.kilos / otherWeight.kilos)

The **__truediv__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It then divides the **kilos** of the weights, creates a new **Weight** object, and returns it.

Let’s test it:

w1 = Weight(50) w2 = Weight(150) res = w1 / w2 print(res.kilos)

Output:

0.333333333333

Now it is possible to divide **Weight** objects by one another.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Dividing Different Types

Let’s try to divide a **Weight** object by an **int**:

w1 = Weight(50) div = w1 / 150 print(div.kilos)

This results in an error:

AttributeError: 'int' object has no attribute 'kilos'

This is not a surprise because we have not specified what should happen when dividing a **Weight** by an integer.

To make the division work, extend the implementation of the **__truediv__()** method:

- If the right-hand side is an
**int**, we can directly divide it by the**kilos**of the**Weight**object. - If the right-hand side is not an
**int**, we assume it is a**Weight**. Then we need to access the**kilos**before the the division.

Here is how it looks in code:

class Weight: def __init__(self, kilos): self.kilos = kilos def __truediv__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos / otherWeight) else: return Weight(self.kilos / otherWeight.kilos)

Now multiplying **Weights** by **ints** works:

w1 = Weight(50) div = w1 / 150 print(div.kilos)

Output:

0.3333333333333333

Awesome!

Now there is still one problem.

When you reverse the order of the division operands:

w1 = Weight(50) div = 150 / w1 print(div.kilos)

You are going to see an error:

TypeError: unsupported operand type(s) for /: 'int' and 'Weight'

Let’s see why this happens.

As you already know, calling **a / b** is the same as calling **a.__truediv__(b)**.

In the above piece of code, you are calling **150 / w1**, that is, **(150).__truediv__(w1)**.

This causes the problem.

Trying to divide an **int** object by a** Weight** does not work because the built-in **int** type has no idea about the **Weight** class.

To fix the problem, you would need to make changes to the built-in **int** type’s **__truediv__** method. But that would be a bad idea.

Instead, Python has a built-in **__rtruediv__()** method you can use to swap the order of the division.

#### The __rtruediv__() Method

The **__rtruediv__()** method stands for “right division”.

It works such that:

- If
**a / b**fails, call**b.__rtruediv__(a)**which is implemented such that**a / b**does not cause problems.

Let’s implement the **__rtruediv__()** method to the **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __truediv__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos / otherWeight) else: return Weight(self.kilos / otherWeight.kilos) def __rtruediv__(self, kilos_int): return Weight(kilos_int / self.kilos)

Now you can divide an **int** by a **Weight** object.

Let’s make sure it works:

w1 = Weight(50) div = 150 / w1 print(div.kilos)

Output:

3.0

It works!

Next, let’s take a look at the integer division, also known as the floor division.

## Integer Division

In Python, you can integer-divide (floor-divide) two numeric types by using the floor division operator (//).

x // y

The floor division divides two numbers and rounds the result down to the nearest integer. The result is thus always an integer.

For example:

>>> 3 // 2 1

### The //= Operator

When floor-dividing variables, you may combine the floor division operator (//) with the assignment operator (=) to form the floor division assignment operator (//=).

x //= y

This is a shorthand for:

x = x // y

For example:

>>> a = 25 >>> a //= 10 >>> a 2

### Precedence

The floor division operator belongs to a higher precedence group than addition and subtraction. This means it takes place before addition or subtraction.

For example:

>>> 5 + 10 // 3 8

Here 10 // 3 is calculated before adding it to 5.

Here is how you can group the operations in your mind:

5 + (10 // 3)

Where expressions inside the parenthesis are calculated first.

Next, let’s take a look at the more advanced use of floor division in Python.

### The __floordiv__() Method

In Python, you can floor-divide numbers to produce an integer that represents the floor division between the two numbers.

Floor division is made possible by the **__floordiv__()** method that is implemented under the hood.

When you use the // operator, you are actually calling the **__floordiv__()** method behind the scenes.

>>> 3 // 2 1 >>> (3).__floordiv__(2) 1

In Python, you can write custom types. This happens by implementing a class that acts as a blueprint for creating objects.

For example, let’s use the **Weight** class from the earlier examples:

class Weight: def __init__(self, kilos): self.kilos = kilos

When you try to floor-divide two **Weight** objects:

w1 = Weight(250) w2 = Weight(100) res = w1 // w2 print(res.kilos)

You receive an error:

TypeError: unsupported operand type(s) for //: 'Weight' and 'Weight'

The error states you cannot apply // on two **Weight** objects.

This is not a real surprise. How could the Python interpreter even know what it means to multiply two weights?

Anyway, there is a way to make it work.

To support floor division between custom types in Python, implement the **__floordiv__()** method into the custom class.

For instance:

class Weight: def __init__(self, kilos): self.kilos = kilos def __floordiv__(self, otherWeight): return Weight(self.kilos // otherWeight.kilos)

The **__floordiv__()** method takes two **Weight** objects:

**self**, the left-hand side of the operator.**otherWeight**, the right-hand side of the operator.

It then floor-divides the **kilos** properties, creates a new **Weight** object, and returns it.

Let’s make sure it works:

w1 = Weight(250) w2 = Weight(100) res = w1 // w2 print(res.kilos)

Output:

2

Now you understand how to floor-division works for custom types.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Floor-Dividing Different Types

Let’s try to floor divide a **Weight** object by an **int**:

w1 = Weight(50) res = w1 // 150 print(res.kilos)

This results in the following error:

AttributeError: 'int' object has no attribute 'kilos'

This is because you have not specified what happens when floor-divide a **Weight** by another object.

To make floor-dividing work this way, you need to extend the implementation of the **__floordiv__()** method:

- If the right-hand side is an
**int**, we can directly floordivide it by the**kilos**property. - If the right-hand side is not an
**int**, we assume it is a**Weight**and access the**kilos**before the division.

Here is what the updated class looks like:

class Weight: def __init__(self, kilos): self.kilos = kilos def __floordiv__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos // otherWeight) else: return Weight(self.kilos // otherWeight.kilos)

Now floor-division between **Weights** and **ints** is possible:

w1 = Weight(250) res = w1 // 150 print(res.kilos)

Output:

1

Now there is still one small issue.

When you reverse the order of the operands:

w1 = Weight(250) res = 150 // w1 print(res.kilos)

There is an error:

TypeError: unsupported operand type(s) for //: 'int' and 'Weight'

As you learned, calling **a // b** is the same as calling **a.__floordiv__(b)**.

Above you are calling **150 // w1**, that is, **(150).__floordiv__(w1)**.

This is the problem.

Trying to floor-divide a **Weight** object by an** int** does not work because the built-in **int** type has no idea about the **Weight** class.

To fix this, you would need to make changes to the native implementation of the **int** type.

However, instead of doing it that way, Python has a built-in **__rfloordiv__()** method you can use to swap the order of the floor division.

#### The __rfloordiv__() Method

The **__rfloordiv__()** method stands for “right floor division”.

The idea is simple:

- If
**a // b**fails, call**b.__rfloordiv__(a)**which is implemented such that**a // b**does not cause problems.

With this in mind, let’s implement the **__rfloordiv__()** method to the **Weight** class:

class Weight: def __init__(self, kilos): self.kilos = kilos def __floordiv__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos // otherWeight) else: return Weight(self.kilos // otherWeight.kilos) def __rfloordiv__(self, kilos_int): return Weight(kilos_int // self.kilos)

Now it works:

w1 = Weight(3) res = 10 // w1 print(res.kilos)

Output:

3

Good job!

Next, let’s take a look at a closely related arithmetic operator, the modulo.

## Modulo

In Python, you can calculate the remainder in division using the modulo operator (%).

x % y

For example, let’s divide 15 pizza slices for 6 guests evenly.

>>> 15 % 6 3

The result is 3.

This means 3 slices of pizza will be leftover.

If you think about it, that makes sense.

Sharing 15 slices of pizza evenly to a group of 6 is not possible. However, you can give 2 slices to each person. At this point, you have shared 12 slices out of 15, so there will be 3 slices left.

### The %= Operator

You can combine the modulo operator (%) with the assignment operator (=) to form the modulo assignment operator (%=).

x %= y

This is a useful shorthand for:

x = x % y

For example:

>>> a = 10 >>> a %= 4 >>> a 2

### Precedence

The modulo belongs to a precedence group that is higher than addition or subtraction. This means modulo takes place before them.

For example:

>>> 20 + 10 % 4 22

Here is how you can group the operations in your mind:

20 + (10 % 4)

Where expressions inside the parenthesis are calculated first.

Next, let’s take a look at the more advanced use of modulo in Python.

### The __mod__() Method

Calculating the modulo is possible via the **__mod__()** method. This method is implemented behind the scenes.

Whenever you use the % operator, you call the **__mod__()** method behind the scenes.

>>> 10 % 4 2 >>> (10).__mod__(4) 2

In Python, you can create a custom type by implementing a class that specifies the type.

For example, let’s continue with the **Weight** class you saw earlier.

class Weight: def __init__(self, kilos): self.kilos = kilos

Let’s see what happens when you try to modulo two **Weight** objects:

w1 = Weight(10) w2 = Weight(4) m = w1 % w2 print(m.kilos)

This shows an error:

TypeError: unsupported operand type(s) for %: 'Weight' and 'Weight'

You cannot apply % between two **Weight** objects. This is because the Python interpreter does not know what it means to take modulo between **Weight** objects.

However, you can separately specify what this means to make it work.

To support modulo between custom types, implement the **__mod__()** method into the custom class.

For instance, let’s make it possible to take a remainder between **Weight** objects based on the **kilos**:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mod__(self, otherWeight): return Weight(self.kilos % otherWeight.kilos)

The **__mod__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It then:

- Calculates the remainder using the
**kilos**of the weights - Creates a new
**Weight**object - Returns the new
**Weight**object.

Let’s test it:

w1 = Weight(10) w2 = Weight(4) m = w1 % w2 print(m.kilos)

Output:

2

It works! However, please notice that this example is pretty useless. It just demonstrates how you can customize the % operator for custom classes in Python.

Now you understand how to calculate modulos between two Python objects.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Calculating Modulo Between Different Types

Let’s try to mod a **Weight** object with an **int**:

w1 = Weight(10) m = w1 % 4 print(m.kilos)

This results in an error:

AttributeError: 'int' object has no attribute 'kilos'

You have not specified what happens when multiplying a **Weight** by another object. This is why you see an error.

To make modulo between different types work, extend the implementation of the **__mod__()** method:

- If the right-hand side is an
**int**, we can directly calculate the modulo using the**kilos**of the weight. - If the right-hand side is not an
**int**, we assume it is a**Weight**. So we need to access the**kilos**before calculating the modulo.

Here is what the updated code looks like:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mod__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos % otherWeight) else: return Weight(self.kilos % otherWeight.kilos)

Now calculating modulo between **Weights** and **ints** is possible:

w1 = Weight(10) m = w1 % 4 print(m.kilos)

Output:

2

Even though this works, there is still one little problem we need to address.

When you reverse the order, that is, when you try to calculate modulo between **int** and a **Weight**:

w1 = Weight(8) m = 20 % w1 print(m.kilos)

You see an error:

TypeError: unsupported operand type(s) for %: 'int' and 'Weight'

Calling **a % b** is the same as calling **a.__mod__(b)**.

Above you are calling **20 % w1**, that is, **(20).__mod__(w1)**.

This is the problem.

Trying to calculate the modulo between an **int** and a** Weight** does not work. This is because the built-in **int** type has no idea about the **Weight** class and what to do with it.

To overcome the issue, you would need to make changes to the native implementation of the **int** type. But as you already know, this is not what you want to do.

Instead, Python has a built-in **__rmod__()** method you can use to swap the order of the operation.

#### The __rmod__() Method

The **__rmod__()** method stands for “right modulo”.

The idea is:

- If
**a % b**fails, call**b.__rmod__(a)**which is implemented such that**a % b**does not cause problems.

Let’s implement the **__rmod__()** method:

class Weight: def __init__(self, kilos): self.kilos = kilos def __mod__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos * otherWeight) else: return Weight(self.kilos * otherWeight.kilos) def __rmod__(self, kilos_int): return Weight(kilos_int % self.kilos)

Now it works:

w1 = Weight(8) m = 20 % w1 print(m.kilos)

Output:

4

Awesome. Last but not least, let’s take a look at the power operator in Python.

## Power

In maths, power means to multiply a number by itself a number of times.

For example:

- 3
^{2}means 3 * 3. - 3
^{4}means 3 * 3 * 3 * 3.

In Python, you can raise a number to a power using the power operator (**).

x ** y

Where:

**x**is the number to be raised.**y**is the number of times x is multiplied by itself.

For example:

>>> 3 ** 2 9

### The **= Operator

When raising variables to power, you may combine the power operator (**) with the assignment operator (=) to form the power assignment operator (**=).

x **= y

This is a shorthand for:

x = x ** y

For example:

>>> a = 2 >>> a **= 3 >>> a 8

### Precedence

In Python, the power operator has the highest precedence of all arithmetic operators.

This means power takes place before multiplication, division, modulo, floor division, addition, or subtraction.

For example:

>>> 10 + 3 * 2 ** 3 / 2 22.0

Here is how you can group the operations in your mind:

10 + (3 * (2 ** 3)) / 2

Where expressions inside the parenthesis are calculated first.

Next, let’s take a look at the more advanced use of powers in Python.

### The __pow__() Method

In Python, you can raise numeric types to a power produce a new value that represents the number multiplied by itself a number of times.

The power operation is made possible by the **__pow__()** method behind the scenes.

Whenever you use the ** operator, you are actually calling the **__pow__()** method.

This is easy to verify.

>>> 3 ** 2 9 >>> (3).__pow__(2) 9

In Python, you can create a custom type by implementing a class that specifies the type.

For example, let’s continue with the **Weight** class from the previous chapters:

class Weight: def __init__(self, kilos): self.kilos = kilos

Now, let’s see what happens when you try to raise a **Weight** object to the power of another **Weight**:

w1 = Weight(2) w2 = Weight(3) p = w1 ** w2 print(p.kilos)

Obviously, this results in an error:

TypeError: unsupported operand type(s) for ** or pow(): 'Weight' and 'Weight'

The error says you cannot use ** on two **Weight** objects. This is because the Python interpreter does not know what it means to raise a **Weight** to the power of another **Weight**.

Anyway, there is a way to make this work.

To support power with custom types in Python, implement the **__pow__()** method into the class.

For example, let’s make it possible to raise a **Weight** object to the power of another Weight via the **kilos** property:

class Weight: def __init__(self, kilos): self.kilos = kilos def __pow__(self, otherWeight): return Weight(self.kilos ** otherWeight.kilos)

The **__pow__()** method takes two **Weight** objects:

**self**, the left-hand side of the operation.**otherWeight**, the right-hand side of the operation.

It then:

- Raises the
**kilos**of the weights to powers accordingly - Creates a new
**Weight**object - Returns the new
**Weight**.

Let’s test that it works:

w1 = Weight(2) w2 = Weight(3) p = w1 ** w2 print(p.kilos)

Output:

8

Now you understand how to raise types to powers in Python.

But what if the left-hand side and the right-hand side objects are not of the same type?

#### Raising Different Types to Power

Let’s try to raise a **Weight** object to the power of an **int**:

w1 = Weight(2) p = w1 ** 3 print(p.kilos)

This throws an error:

AttributeError: 'int' object has no attribute 'kilos'

This happens because you have not specified what happens when raising a **Weight** to the **int** power.

To make it work, extend the implementation of the **__pow__()** method:

- If the right-hand side is an
**int**, we can directly raise the**kilos**of the weight to the power of the integer value. - If the right-hand side is not an
**int**, we assume it is a**Weight**. So we need to access the**kilos**before the raising it.

Here is what the code looks like after the updates:

class Weight: def __init__(self, kilos): self.kilos = kilos def __pow__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos ** otherWeight) else: return Weight(self.kilos ** otherWeight.kilos)

Now you can test it:

w1 = Weight(2) p = w1 ** 3 print(p.kilos)

Output:

8

Now there is one more problem to be solved.

When you reverse the order, that is, when you try to raise an **int** to the power of **Weight**:

w1 = Weight(2) p = 3 ** w1 print(p.kilos)

You get an error:

TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'Weight'

Let’s see why this error happens.

Calling **a ** b** is the same as calling **a.__pow__(b)**.

Here you are calling **3 ** w1**, that is, **(3).__pow__(w1)**.

This is problematic because the **int** type does not know anything about the **Weight** class.

To overcome the issue, you would need to make changes to the built-in **int** type. But this would be bad.

Instead, Python has a built-in **__rpow__()** method you can use to swap the order of the operation.

#### The __rpow__() Method

The **__rpow__()** method stands for “right power”.

The working principle is simple:

- If
**a ** b**fails, call**b.__rpow__(a)**which is implemented such that**a ** b**does not cause problems.

With this information, let’s implement the **__rpow__()**:

class Weight: def __init__(self, kilos): self.kilos = kilos def __pow__(self, otherWeight): if type(otherWeight) == int: return Weight(self.kilos ** otherWeight) else: return Weight(self.kilos ** otherWeight.kilos) def __rpow__(self, kilos_int): return Weight(kilos_int ** self.kilos)

Now it works:

w1 = Weight(2) p = 3 ** w1 print(p.kilos)

Output:

9

Awesome!

## Conclusion

This concludes the comprehensive guide on all the arithmetic operators in Python.

Thanks for reading.

Happy coding!