Math Magic Methods | Magic Methods
In-Depth Python OOP

# Math Magic Methods

There are additional magic methods for various math operations in Python. In addition to the `__add__` magic method, which is used for addition, there are other magic methods for different mathematical operations:

 Magic Method Operation `__add__(self, other)` `+` `__sub__(self, other)` `-` `__mul__(self, other)` `*` `__pow__(self, other)` `**` `__mod__(self, other)` `%` `__truediv__(self, other)` `/` `__floordiv__(self, other)` `//`

These magic methods typically receive two arguments: `self` (representing the instance, which is the right operand in the expression) and `other` (representing the left operand in the expression). By convention, it is common to refer to the second argument as `other` or `other_obj`, but you have the flexibility to use a different name if it makes the code more meaningful or clear in the context of your class and its operations. The name of the second argument should reflect its purpose and role in the mathematical operation being implemented.

Let's look at the example with `int` object:

Code Description
In Python, when the multiplication operator (`*`) is used between two objects, Python looks for the `__mul__` method of the left-hand operand (if it exists) to perform the multiplication. If the `__mul__` method is defined for that object, Python uses it to compute the result of the multiplication.

So, in the given code, both `a * b` and `a.__mul__(b)` are equivalent and will produce the same result, which is 25 * 12 = 300. Python uses the `__mul__` method of the `int` class internally when the multiplication operator is used with integers.

Creating a magic method in Python allows us to define custom logic for mathematical operators. Typically, these methods return a new instance of the class where certain attributes are added, multiplied, divided, etc. For example, in a `Road` class, the `+` operator could return a new road with the added length, as discussed in the first chapter of this section.

Let's improve the example from the first chapter of this section:

Code Description
The `Road` class has implemented the `__add__` method, which is the addition operator (`+`) in Python. This method allows objects of the `Road` class to be added together using the `+` operator.

The `__add__` method first checks if the `other` object is an instance of the `Road` class using the `isinstance()` function. If it is, it creates a new `Road` object with a length equal to the sum of the lengths of the current `Road` object (`self.length`) and the `other` `Road` object (`other.length`).

If the `other` object is not an instance of the `Road` class, it assumes that `other` is a numeric value and creates a new `Road` object with a length equal to the sum of the length of the current `Road` object (`self.length`) and the `other` value.

In both cases, the `__add__` method returns the newly created `Road` object representing the combined road.

In summary, the `__add__` method of the `Road` class allows two `Road` objects to be added together using the `+` operator, resulting in a new `Road` object with a length equal to the sum of their lengths. It also allows a numeric value to be added to a `Road` object, resulting in a new `Road` object with a length equal to the sum of the road's length and the numeric value.

Compared to Java or JavaScript, in Python, instead of defining a regular method `add` to add classes, we can change the behavior of the `+` operator, which is much more convenient to use (`instance1 + instance2`) than calling `instance1.add(instance2)` every time.

Which magic method should be used?

Everything was clear?

Section 5. Chapter 3

Course Content

In-Depth Python OOP

# Math Magic Methods

There are additional magic methods for various math operations in Python. In addition to the `__add__` magic method, which is used for addition, there are other magic methods for different mathematical operations:

 Magic Method Operation `__add__(self, other)` `+` `__sub__(self, other)` `-` `__mul__(self, other)` `*` `__pow__(self, other)` `**` `__mod__(self, other)` `%` `__truediv__(self, other)` `/` `__floordiv__(self, other)` `//`

These magic methods typically receive two arguments: `self` (representing the instance, which is the right operand in the expression) and `other` (representing the left operand in the expression). By convention, it is common to refer to the second argument as `other` or `other_obj`, but you have the flexibility to use a different name if it makes the code more meaningful or clear in the context of your class and its operations. The name of the second argument should reflect its purpose and role in the mathematical operation being implemented.

Let's look at the example with `int` object:

Code Description
In Python, when the multiplication operator (`*`) is used between two objects, Python looks for the `__mul__` method of the left-hand operand (if it exists) to perform the multiplication. If the `__mul__` method is defined for that object, Python uses it to compute the result of the multiplication.

So, in the given code, both `a * b` and `a.__mul__(b)` are equivalent and will produce the same result, which is 25 * 12 = 300. Python uses the `__mul__` method of the `int` class internally when the multiplication operator is used with integers.

Creating a magic method in Python allows us to define custom logic for mathematical operators. Typically, these methods return a new instance of the class where certain attributes are added, multiplied, divided, etc. For example, in a `Road` class, the `+` operator could return a new road with the added length, as discussed in the first chapter of this section.

Let's improve the example from the first chapter of this section:

Code Description
The `Road` class has implemented the `__add__` method, which is the addition operator (`+`) in Python. This method allows objects of the `Road` class to be added together using the `+` operator.

The `__add__` method first checks if the `other` object is an instance of the `Road` class using the `isinstance()` function. If it is, it creates a new `Road` object with a length equal to the sum of the lengths of the current `Road` object (`self.length`) and the `other` `Road` object (`other.length`).

If the `other` object is not an instance of the `Road` class, it assumes that `other` is a numeric value and creates a new `Road` object with a length equal to the sum of the length of the current `Road` object (`self.length`) and the `other` value.

In both cases, the `__add__` method returns the newly created `Road` object representing the combined road.

In summary, the `__add__` method of the `Road` class allows two `Road` objects to be added together using the `+` operator, resulting in a new `Road` object with a length equal to the sum of their lengths. It also allows a numeric value to be added to a `Road` object, resulting in a new `Road` object with a length equal to the sum of the road's length and the numeric value.

Compared to Java or JavaScript, in Python, instead of defining a regular method `add` to add classes, we can change the behavior of the `+` operator, which is much more convenient to use (`instance1 + instance2`) than calling `instance1.add(instance2)` every time.

Which magic method should be used?