Python Operator Overloading and Python Magic Methods
Master Python with 70+ Hands-on Projects and Get Job-ready - Learn Python
In this Python tutorial, we are going to discuss Python Operator Overloading, examples of operator overloading in python, and python magic methods with some operators: python binary operator, python comparison operator, python unary operators, and python extended assignments.
In the programming world, operator overloading is also called Operator Ad-hoc Polymorphism.
Indeed, it is a case of polymorphism where different operators have different implementations based on their arguments.
This is either defined by the programmer, by the programming language, or both.
So, let’s start the Python Magic Methods Tutorial.
What is Python Operators Overloading?
In Python, an operator lets us perform an operation/procedure on one or more operands(values). Let’s take an example.
>>> 42+1
Output
Here, we performed the addition of two numbers using the addition operator.
You know that we can apply this operator to Python string too. In that case, we call it the concatenation operator.
>>> '42'+'1'
Output
>>> 'hello'+' '+'world'
Output
And then when we do this to Python list, we concatenate two lists.
>>> [1,2,3]+[4,5,6]
Output
Python does this implicitly, but what for when you want to apply this operator to your own class? Can we? Let’s give it a try.
In this python operator overloading tutorial, we take a class ‘myfloat’ to represent floating-point numbers.
>>> class myfloat:                def __init__(self,whole,fraction):                       self.whole=whole                       self.fraction=fraction            def shownumber(self):                       print(f"I am {self.whole}.{self.fraction}") >>> obj1=myfloat(3,7) >>> obj1.shownumber()
Output
>>> obj2=myfloat(3,3) >>> obj2.shownumber()
Output
Now, let’s try adding two objects.
>>> obj1+obj2
Output
Traceback (most recent call last):
File “<pyshell#24>”, line 1, in <module> obj1+obj2TypeError: unsupported operand type(s) for +: ‘myfloat’ and ‘myfloat’
As you can see, this raised a TypeError. But don’t fret; we can do this, we’ll discuss in a later section.
Python Magic Methods
We observe that python methods have double underscores before and after their names. These are special methods and are also called ‘dunders’.
These help us implement functionality that a normal method can’t represent.
By now, we have come across only one magic method- __init__(). But we can, in fact, define our own magic methods to implement operator overloading in Python.
With this, we can define these operators to work on our custom classes. Some of these are-
1. Python Binary Operators
__add__ for +
__sub__ for –
__mul__ for *
__truediv__ for /
__floordiv__ for //
__mod__ for %
__pow__ for **
__and__ for &
__xor__ for ^
__or__ for |
__lshift__ for <<
__rshift__ for >>
2. Python Extended Assignments
__iadd__ for +=
__isub__ for -=
__imul__ for *=
__idiv__ for /=
__ifloordiv__ for //=
__imod__ for %=
__ipow__ for **=
__ilshift__ for <<=
__irshift__ for >>=
__iand__ for &=
__ixor__ for ^=
__ior__ for |=
3. Python Unary Operators
__neg__ for –
__pos__ for +
__abs__ for abs()
__invert__ for ~
__complex__ for complex()
__int__ for int()
__long__ for long()
__float__ for float()
__oct__ for oct()
__hex__ for hex()
4. Python Comparison Operators
__lt__ for <
__le__ for <=
__eq__ for ==
__ne__ for !=
__ge__ for >=
__gt__ for >
Others include __radd__ for reverse add.
>>> class myclass: def __init__(self,age): self.age=age def __add__(self,other): return self.age+other def __radd__(self,other): return self.age+other >>> a=myclass(1) >>> a+2
Output
>>> 2+a
Output
If the interpreter cannot add left to right, it will call __radd__() instead. Here, radd is in reverse/reflected add.
Python Operator Overloading Example
To be able to add our Python objects obj1 and obj2 for class ‘myfloat’, we can do the following.
>>> class myfloat:                def __init__(self,whole,fraction):            self.whole=whole            self.fraction=fraction          def shownumber(self):                                print(f"I am {self.whole}.{self.fraction}")         def __add__(self,other):                 if (self.fraction+other.fraction)>9:                                        return myfloat(self.whole+other.whole+1,self.fraction+other.fraction-10)            return myfloat(self.whole+other.whole,self.fraction+other.fraction)
Here, we added another method __add__, that takes two parameters (‘self’ and ‘other’) for the two objects.
Then, it checks if the sum of the fraction parts of both objects is greater than 9. In that case, it transfers a 10 to the ‘whole’ part as a 1.
This is for the carry. It then returns an object with the sums of the whole and fraction parts of both objects.
However, if the condition isn’t met, it simply returns an object with the sums.
Let’s create objects obj1 and obj2 again, and try adding them.
>>> obj1=myfloat(3,7) >>> obj1.shownumber()
Output
>>> obj2=myfloat(3,3) >>> obj2.shownumber()
Output
>>> result=obj1+obj2 >>> print(f"I am {result.whole}.{result.fraction}")
Output
As you can see, it works absolutely fine now and lets us add two objects of class ‘myfloat’.
>>> result
Output
This is the resulting object of adding obj1 and obj2.
Here, the interpreter translates obj1+obj2 to obj1.__add__(obj2).
More Examples of Python Operator Overloading
To really understand something, once is never enough. So, let’s take another example of Operator overloading in Python.
>>> class itspower:                def __init__(self,x):                                self.x=x                def __pow__(self,other):                                return self.x**other.x             >>> a=itspower(2) >>> b=itspower(10) >>> a**b
Output
In this, we take a class ‘itspower’ and two methods __init__ and __pow__.
__pow__ takes two objects and returns the ‘x’ of first raised to the power of the ‘x’ of the second.
When we type a**b, the interpreter converts it implicitly to a.__pow__(b).
Now, let’s take another example to demonstrate few more such magic methods.
>>> class Person: def __init__(self,name,age): self.name=name self.age=age def __gt__(self,other): if self.age>other.age: return True return False def __abs__(self): return abs(self.age) def __iadd__(self,other): return self.age+other.age >>> Nick=Person('Nick',7) >>> Angela=Person('Angela',5) >>> Nick>Angela
Output
>>> Kim=Person('Kim',-8) >>> abs(Kim)
Output
>>> Tom=Person('Tom',7) >>> Mikayla=Person('Mikayla',3) >>> Tom+=Mikayla >>> Tom
Output
To leave this lesson on an engaging note, we would just like to leave this code here:
>>> '1'.__add__('1')
Output
>>> 1.__add__(1)
Output
>>> [1,2,3].__add__([4,5,6])
Output
So, this was all about Python Operator overloading and Python Magic Method Tutorial. Hope you like it.
Interview Questions on Python Operator Overloading and Python Magic Methods
- How do you overload an operator in Python?
- What are the magical methods in Python?
- Which operator is overloaded by invert in Python?
- How do you call a magic method in Python?
- Which operators cannot be overloaded?
Conclusion
Hence, we studied Python Operator overloading, in-effect, is pure syntactic sugar. Through it, we override a magic method to be able to use an operator on a custom class.
Did you know we work 24x7 to provide you best tutorials
Please encourage us - write a review on Google
Hi,i oveloaded negation operator like this.
def __neg__(self):
return -self.x
-ob1
print(ob1)
but not getting it could you help me to resolve this.
Hello Srinivas,
Let this be your class:
class A:
def __init__(self,x):
self.x=x
def __neg__(self):
return -self.x
Now, create an object of this class:
ob1=A(7)
And now, perform negation on it:
print(-ob1)
And you’ll have -7. It negated the value of x- we can rephrase this to say it negated the object ob1.
Hope, this will solve your query. Keep visiting DataFlair
why 1.__add__(1) is getting error?
For understanding this, you will have to go at a little depth.
The python tokenizer tries to build the longest possible token. so the line is split into tokens as
“1.”, “__add__”, “(“,”1″ ,”)”
It parses the first token as “1.” which is a float value followed by an identifier. So, it throws syntax error.
Note: (1).__add__(1) will return 2
Why class names are in lowercase? Earlier lessons mentioned that CAPS should be used for classes and exceptions?
Yes classes and exception names should start with Capital letter but in this article we are studying operator overloading which is a different than normal classes, hence the class names are in lowercase.