Welcome to part 10 of my Learn to Program series. In this part of the tutorial I’ll cover Inheritance, Operator Overloading, Polymorphism and Magic Methods, which are super awesome! If you missed previous parts of this tutorial watch those videos first.
All of the code along with a transcript from the video can be found below the video that follows.
If you value videos like this consider contributing on Patreon.
[googleplusone]
Code & Transcript
# When we create a class we can inherit all of the fields and methods
# from another class. This is called inheritance.
# The class that inherits is called the subclass and the class we
# inherit from is the super class
# This will be our super class
class Animal:
def __init__(self, birthType="Unknown",
appearance="Unknown",
blooded="Unknown"):
self.__birthType = birthType
self.__appearance = appearance
self.__blooded = blooded
# The getter method
@property
def birthType(self):
# When using getters and setters don't forget the __
return self.__birthType
@birthType.setter
def birthType(self, birthType):
self.__birthType = birthType
@property
def appearance(self):
return self.__appearance
@appearance.setter
def appearance(self, appearance):
self.__appearance = appearance
@property
def blooded(self):
return self.__blooded
@blooded.setter
def blooded(self, blooded):
self.__blooded = blooded
# Can be used to cast our object as a string
# type(self).__name__ returns the class name
def __str__(self):
return "A {} is {} it is {} it is " \
"{}".format(type(self).__name__,
self.birthType,
self.appearance,
self.blooded)
# Create a Mammal class that inherits from Animal
# You can inherit from multiple classes by separating
# the classes with a comma in the parentheses
class Mammal(Animal):
def __init__(self, birthType="born alive",
appearance="hair or fur",
blooded="warm blooded",
nurseYoung=True):
# Call for the super class to initialize fields
Animal.__init__(self, birthType,
appearance,
blooded)
self.__nurseYoung = nurseYoung
# We can extend the subclasses
@property
def nurseYoung(self):
return self.__nurseYoung
@nurseYoung.setter
def appearance(self, nurseYoung):
self.__nurseYoung = nurseYoung
# Overwrite __str__
# You can use super() to refer to the superclass
def __str__(self):
return super().__str__() + " and it is {} they nurse " \
"their young".format(self.nurseYoung)
class Reptile(Animal):
def __init__(self, birthType="born in an egg or born alive",
appearance="dry scales",
blooded="cold blooded"):
# Call for the super class to initialize fields
Animal.__init__(self, birthType,
appearance,
blooded)
# Operator overloading isn't necessary in Python because
# Python allows you to enter unknown numbers of values
# Always make sure self is the first attribute in your
# class methods
def sumAll(self, *args):
sum = 0
for i in args:
sum += i
return sum
def main():
animal1 = Animal("born alive")
print(animal1.birthType)
# Call __str__()
print(animal1)
print()
mammal1 = Mammal()
print(mammal1)
print(mammal1.birthType)
print(mammal1.appearance)
print(mammal1.blooded)
print(mammal1.nurseYoung)
print()
reptile1 = Reptile()
print(reptile1.birthType)
print(reptile1.appearance)
print(reptile1.blooded)
print()
# Operator overloading in Python
print("Sum : {}".format(reptile1.sumAll(1,2,3,4,5)))
# Polymorphism in Python works differently from other
# languages in that functions accept any object
# and expect that object to provide the needed method
# This isn't something to dwell on. Just know that
# if you call on a method for an object that the
# method just needs to exist for that object to work.
# Polymorphism is a big deal in other languages that
# are statically typed (type is defined at declaration)
# but because Python is dynamically typed (type defined
# when a value is assigned) it doesn't matter as much.
def getBirthType(theObject):
print("The {} is {}".format(type(theObject).__name__,
theObject.birthType))
getBirthType(mammal1)
getBirthType(reptile1)
main()
# ---------- MAGIC METHODS ----------
# Magic methods are surrounded by double underscores
# We can use magic methods to define how operators
# like +, -, *, /, ==, >, <, etc. will work with our
# custom objects
# Magic methods are used for operator overloading
# in Python
# __eq__ : Equal
# __ne__ : Not Equal
# __lt__ : Less Than
# __gt__ : Greater Than
# __le__ : Less Than or Equal
# __ge__ : Greater Than or Equal
# __add__ : Addition
# __sub__ : Subtraction
# __mul__ : Multiplication
# __div__ : Division
# __mod__ : Modulus
class Time:
def __init__(self, hour=0, minute=0, second=0):
self.hour = hour
self.minute = minute
self.second = second
# Magic method that defines the string format of the object
def __str__(self):
# :02d adds a leading zero to have a minimum of 2 digits
return "{}:{:02d}:{:02d}".format(self.hour,self.minute, self.second)
def __add__(self, other_time):
new_time = Time()
# ---------- PROBLEM ----------
# How would you go about adding 2 times together?
# Add the seconds and correct if sum is >= 60
if (self.second + other_time.second) >= 60:
self.minute += 1
new_time.second = (self.second + other_time.second) - 60
else:
new_time.second = self.second + other_time.second
# Add the minutes and correct if sum is >= 60
if (self.minute + other_time.minute) >= 60:
self.hour += 1
new_time.minute = (self.minute + other_time.minute) - 60
else:
new_time.minute = self.minute + other_time.minute
# Add the minutes and correct if sum is > 60
if (self.hour + other_time.hour) > 24:
new_time.hour = (self.hour + other_time.hour) - 24
else:
new_time.hour = self.hour + other_time.hour
return new_time
def main():
time1 = Time(1, 20, 30)
print(time1)
time2 = Time(24, 41, 30)
print(time1 + time2)
# For homework get the Time objects to work for the other
# mathematical and comparison operators
main()