Python Polymorphism Python Operator Overloading and Magic Methods

python polymorphism


Python Polymorphism – Poly means many and morphism means forms. Python Polymorphism is one of the tenets of Object-Oriented Programming (OOP). Python Polymorphism means that you can have multiple classes where each class implements the same variables or methods in different ways. Python Polymorphism takes advantage of inheritance in order to make this happen. A real-world

example of python Polymorphism is supposed when if you are in a classroom that time you behave like a student when you are in the market at that time you behave like a customer, when you are at your home at that time you behave like a son or daughter, such that same person is presented as having different behaviors. Python is a dynamically-typed language and specifically uses duck-typing. The term duck-typing comes from the idiomatic saying, “If it looks like a duck and quacks like a duck, it is probably a duck.” Duck-typing in Python allows us to use any object that provides the required methods and variables without forcing it to belong to any particular class. In duck-typing, an object’s suitability is determined by the presence of methods and variables rather than the actual type of the object. To elaborate, this means that the expression will succeed if object some_obj has a foo method, regardless of to which class some_obj object actually belongs to. Difference between inheritance and polymorphism is, while inheritance is implemented on classes, python Polymorphism is implemented on methods.

Program to Demonstrate  Python Polymorphism:


python polymorphism

Even though each of these methods in the classes have the same name, their implementation details are different. Polymorphic behavior allows you to specify common methods in a base class and implement them differently in other derived classes. In this program, we defined two derived classes, Bike and Car, inherited from vehicle class, and provided their own implementation of vehicle_model() method on top of vehicle_model() method found in

Vehicle class. Notice that all the classes have vehicle_model() method but they are implemented differently. The method vehicle_model() is polymorphic, as these methods have the same name but belong to different classes and are executed depending on the object. The behavior of the same method belonging to different classes is different based on the type of object. To allow python Polymorphism, a common interface called vehicle_info() – function is created

that can take an object of any type and call that object’s vehicle_model() method. When you pass the objects ducati and beetle to the vehicle_info() function, it executes vehicle_model() method effectively. Because of python Polymorphism, the run-time type of each object is invoked. In the for loop, you iterate through each object in the list using each_obj

as the iterating variable. Depending on what type of object it has, the program decides which methods it should use. If that object does not have the methods that are called, then the function signals a run-time error. If the object does have the methods, then they are executed no matter the type of the object, evoking the quotation and, hence, the name of this form of typing. Since object boeing has no vehicle_model() method associated with it, an exception is raised.

Write Python Program to Calculate Area and Perimeter of Different Shapes Using Python Polymorphism


In the above program, Shape is the base class while Rectangle  and Circle  are the derived classes. All of these classes have common methods area() and perimeter() added to them but their implementation is different as found in each class. Derived classes Rectangle and Circle have their own data attributes. Instance variables rectangle_obj and circle_obj are created for Rectangle and Circle classes respectively. The clearest way to express python Polymorphism is through the function shape_type() , which takes any object and invokes the methods area() and perimeter() respectively.

Python Operator Overloading and Magic Methods

Operator Overloading is a specific case of python Polymorphism, where different operators have different implementations depending on their arguments. A class can implement certain operations that are invoked by special syntax (such as arithmetic operations or subscripting and slicing) by defining methods with special names called “Magic Magic Methods for Different Operators and Functions.

Python Binary Operators:

+ __add__(self, other):

 Invoked for Addition Operations

– __sub__(self, other):

 Invoked for Subtraction Operations

* __mul__(self, other):

 Invoked for Multiplication Operations

/ __truediv__(self, other):

 Invoked for Division Operations

__floordiv__(self, other):

 Invoked for Floor Division Operations

% __mod__(self, other) :

Invoked for Modulus Operations

** __pow__(self, other[, modulo]):

 Invoked for Power Operations

<< __lshift__(self, other) :

Invoked for Left-Shift Operations

>> __rshift__(self, other) :

Invoked for Right-Shift Operations

& __and__(self, other):

 Invoked for Binary AND Operations

^ __xor__(self, other):

 Invoked for Binary Exclusive-OR Operations

| __or__(self, other):

 Invoked for Binary OR Operations

Python Extended Operators

+= _iadd__(self, other):

 Invoked for Addition Assignment Operations

-= __isub(self, other) :

Invoked for Subtraction Assignment Operations

*= __imul__(self, other):

 Invoked for Multiplication Assignment Operations

/= __idiv__(self, other):

 Invoked for Division Assignment Operations

//= __ifloordiv__(self, other) :

Invoked for Floor Division Assignment Operations

%= __imod__(self, other) :

Invoked for Modulus Assignment Operations

**= __ipow__(self, other[, modulo]):

 Invoked for Power Assignment Operations

<<= __ilshift__(self, other):

 Invoked for Left-Shift Assignment Operations

>>= __irshift__(self, other):

 Invoked for Right-Shift Assignment Operations

&= __iand__(self, other) :

Invoked for Binary AND Assignment Operations

classes to define their own behavior with respect to language operators. Python uses\ the word “Magic Methods” because these are special methods that you can define to add magic to your program. These magic methods start with double underscores and end with double underscores. One of the biggest advantages of using Python’s magic methods is that they provide a simple way to make objects behave like built-in types. That means you can avoid ugly, counter-intuitive, and nonstandard ways of using basic operators. The basic rule of operator overloading in Python is, Whenever the meaning of an operator is not obviously clear and undisputed, it should not be overloaded and always stick to the operator’s well-known semantics.

 You cannot create new operators\ and you can’t change the meaning of operators for built-in types in Python programming language. Consider the standard + (plus) operator. When this operator is used with operands of different standard types, it will have a different meaning. The + operator performs arithmetic addition of two numbers, merges two lists, and concatenates two strings.

^= __ixor__(self, other) :

Invoked for Binary Exclusive-OR Assignment Operations

|= __ior__(self, other):

 Invoked for Binary OR Assignment Operations

Python Unary Operators

– __neg__(self) :

Invoked for Unary Negation Operator

+ __pos__(self) :

Invoked for Unary Plus Operator

abs() __abs__():

 Invoked for built-in function abs(). Returns absolute value

~ __invert__(self):

 Invoked for Unary Invert Operator

Python Conversion Operations

complex() __complex__(self) :

Invoked for built-in complex() function

int() __int__(self):

 Invoked for built-in int() function

long() __long__(self):

 Invoked for built-in long() function

float() __float__(self) :

Invoked for built-in float() function

oct() __oct__() :

Invoked for built-in oct() function

hex() __hex__():

 Invoked for built-in hex() function

Python Comparison Operators

< __lt__(self, other):

 Invoked for Less-Than Operations

<= __le__(self, other) :

Invoked for Less-Than or Equal-To Operations

== __eq__(self, other) :

Invoked for Equality Operations

!= __ne__(self, other) :

Invoked for Inequality Operations

>= __ge__(self, other) :

Invoked for Greater Than or Equal-To Operations

> __gt__(self, other):

 Invoked for Greater Than Operations

Python Polymorphism example: Write Python Program to Create a Class Called as Complex and Implement __add__() Method to Add Two Complex Numbers. Display the Result by Overloading the + Operator:


python polymorphism

Consider the below code having Complex class with real and imaginary as data attributes class Complex:

def __init__(self, real, imaginary):

self.real = real

self.imaginary = imaginary

Instance variables complex_number_1 and complex_number_2 are created for Complex class.

complex_number_1 = Complex(4, 5)

complex_number_2 = Complex(2, 3)

complex_number_sum = complex_number_1 + complex_number_2

If you try to add the objects complex_number_1 and complex_number_2 then it results in error as shown below.

TypeError: unsupported operand type(s) for +: ‘Complex’ and ‘Complex’

Adding the magic method __add__()  within the Complex class resolves this issue. The __add__() method takes two objects as arguments with complex_number_1 object assigned to self and complex_number_2 object assigned to other and it is expected to return the result of the computation. When the expression complex_number_1 + complex_number_2 is executed, Python will call complex_number_1.__add__(complex_number_2).

def __add__(self, other):

return Complex(self.real + other.real, self.imaginary + other.imaginary) Thus, by adding this method, suddenly magic has happened and the error, which you received earlier, has gone away. This method returns the Complex object itself by calling the Complex class __init__() constructor, with self.real + other.real value assigned to real data attribute and self.imaginary + other.imaginary value assigned to the imaginary data attribute.

The __add__() method definition has your own implementation. This returning object is assigned to complex_number_sum with data attributes real and imaginary. To print the data attributes associated with complex_number_sum object, you have to issue the statements print(complex_number_sum.real) and print(complex_number_sum.imaginary). Instead of issuing the above statements, you can use the object name only within the print statement, for example, print(complex_number_sum) to print its associated data attributes.

This is done by overriding __str__() magic method. The syntax is __str__(self). The __str__() method is called by str(object) and the built-in functions format() and print() to compute the “informal,” or nicely printable string representation of an object. The return value must be a string object. The implementation details of __str__() magic method is shown below

def __str__(self):

return f”{self.real} + i{self.imaginary}”

The return value of __str__() method has to be a string, but it can be any string, including one that contains the string representation of integers. In the implementation of the __ str__() magic method, you have customized it for your own purpose. The __str__() method returns a string with values of real and imaginary data attributes concatenated together, and the character i is prefixed before imaginary data attribute value.

Python Polymorphism example: Write a program which Checks Whether the Area of the First Rectangle is Greater than Second by Overloading > Operator


python polymorphism

In the above code, rectangle_1_obj _ and rectangle_2_obj are the objects of Rectangle class When the expression if rectangle_1_obj > rectangle_2_obj is executed, the magic method rectangle_1_obj.__gt__(rectangle_2_obj) gets invoked. This magic method calculates the area of two rectangles and returns a Boolean True value if the area of the first rectangle is greater than the area of the second rectangle.

Related Article:

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button