Attribution
This page originates from TeachBooks/learn-programming, version: mude-2025
import matplotlib
if not hasattr(matplotlib.RcParams, "_get"):
matplotlib.RcParams._get = dict.get
1.5. Polymorphism#
Another important goal of the object-oriented approach to programming is to provide flexibility of your code. This can be achived by Polymorphism, which entails that an entity is able to take multiple forms. In Python polymorphism allows us to create methods in a child class with the same name as a method in a parent class. This would mean that a method can serve one purpose in a parent class and different one in a child class.
Child classes inherit all the methods of their parent classes, however, sometimes those methods need to be modified to fit the function of the child. This is achieved by reimplementing the parent methods in the child class.
To better understand polymorphism, let’s look at an example of a class that can be based on the Shuttle class and transitively on the Rocket class as well.
The ImprovedShuttle class#
Our Shuttle class already improves the basic Rocket class, however, the information we receive from the Rocket class such as get_distance is very limited. This is because we currently only get information about the absolute distance, but we do not know the direction, which we need to face to get to that place the fastest.
Therefore, we will create an improved Shuttle, which will be based on the initial Shuttle and will provide better distance information such as angle in which we need to rotate. The formula used is based on taking arctangent of the 2-dimension distances and transforming from radians to degrees.
Here is what the ImprovedShuttle class looks like:
from math import sqrt
import datetime
class Rocket:
# Rocket simulates a rocket ship for a game,
# or a physics simulation.
def __init__(self, x=0, y=0):
# Each rocket has an (x,y) position.
self.x = x
self.y = y
self.__creation_time = datetime.datetime.now()
def move_rocket(self, x_increment=0, y_increment=1):
# Move the rocket according to the paremeters given.
# Default behavior is to move the rocket up one unit.
self.x += x_increment
self.y += y_increment
def get_distance(self, other_rocket):
# Calculates the distance from this rocket to another rocket,
# and returns that value.
distance = sqrt((self.x-other_rocket.x)**2+(self.y-other_rocket.y)**2)
return distance
def get_creation_time(self):
# Returns the time the Rocket was made.
return self.__creation_time
class Shuttle(Rocket):
# Shuttle simulates a space shuttle, which is really
# just a reusable rocket.
def __init__(self, x=0, y=0, flights_completed=0):
super().__init__(x, y)
self.flights_completed = flights_completed
from math import atan, pi, sqrt
class ImprovedShuttle(Shuttle):
# Improved Shuttle that provides better distance information
# such as angle.
def __init__(self, x=0, y=0, flights_completed=0):
super().__init__(x, y)
self.flights_completed = flights_completed
def get_distance(self, other_rocket):
# Calculates the distance from this rocket to another rocket,
# the angle to rotate to face the other rocket,
# and returns those values.
distance = super().get_distance(other_rocket)
angle = atan((other_rocket.y - self.y) / (other_rocket.x - self.x)) * (180 / pi)
return distance, angle
improvedShuttle = ImprovedShuttle(10,0,3)
otherShuttle = ImprovedShuttle(13, 3)
# Show the distance between them.
distance, angle = improvedShuttle.get_distance(otherShuttle)
print(f"The shuttles are {distance:.6f} units apart.")
print(f"The angle the initial shuttle needs to rotate in case it needs to go to the other shuttle is {angle:.2f} degrees.")
The shuttles are 4.242641 units apart.
The angle the initial shuttle needs to rotate in case it needs to go to the other shuttle is 45.00 degrees.
As you can see in the example above, since ImprovedShuttle inherits Shuttle and Shuttle inherits Rocket, then transitively ImprovedShuttle is a child of Rocket class and has access to the parent get_distance method. It is possible to access that parent method by making a super().get_distance() call.
As a result, class ImprovedShuttle has overridden Rocket’s get_distance. This means that it has reimplemented the parent’s method.
It is important to mention that it is not necessary to override (reimplement) every method in the parent class when using inheritance, but if needed, it is possible.
Note
ImprovedShuttle’s get_distance() now returns two outputs, while the parent class only returns one. Imagine you are looping a list containing a mix of Rockets and ImprovedShuttles to store their distance in an array (with as many elements as the length of the lists); this difference in the output may require some extra lines of code to handle potential problems.