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:
- 32 means 3 * 3.
- 34 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!