Parent, child class, methods override Polymorphism
Chapter 12 Inheritance
In Object Oriented Programming(OOP), a great benefit is to reuse code. Inheritance is one way to achieve this.
12.1 Parent and Child Class
Inheritance enables us to make new class based on an existing class. The new class(child class or subclass) will inherit all the attributes of the existing class(parent class or superclass), and on top of that, a child class can also override attributes from the parent class or have extra features of its own.
Syntax Child class is declared as usual class, only has a parentheses after it's name with Parent class name inside:
class Parent:
code...
class Child(Parent):
code...
Given that Child class inherits from the Parent class, we can say the following:
- Child is derived from Parent
- Child extends Parent
- Parent is a superclass of Child; Child is a subclass of Parent
- Child isa Parent (Wait to see examples to understand this)
Let's use the example of Pet class, Cat class and Parakeet class. Cat and parakeet are all pets. Pet is the parent class, it has 4 fields: name, color, type, and legNumber. Cat and Parakeet are both child classes that derived from Pet class. They all inherit the 4 fields from Pet, but they both have some new feature of their own.
Ex. 12.1-1 PetCat.py
The file named PetCat.py
(module) contains two classes: Pet and Cat
# PetCat.py
Class Pet:
def __init__ (self, n=' ', c=' ', t=' ', a=0):
self.name = n
self.color = c
self.type = t
self.age = a
def setName (self, n ):
self.name = n
def getName (self):
return self.name
def setColor (self, c ):
self.color = c
def getColor (self):
return self.age
def setType (self, t ):
self.type = t
def getType (self):
return self.type
def setAge (self, a)
self.Age = a
def getAge (self):
return "{0} years".format(self.age)
def __str__ (self):
return "{0} is a {1} {2} aged {3} years.".format (self.name, self.color, self.type, self.age)
class Cat( Pet ): # Cat is a child class, Pet is the parent class
def __init__ (self, n=' ', c=' ', a=0):
self.name = n
self.color = c
self.type = 'cat'
self.age = a
def setType (self, t)
print ('{0} refuses to change type, it will always be a {1} in this life.'. format (self.name, self.type) )
def setAge(self, a):
if 1<= a <30:
self.age = a
Pet
class has four things common to all pets: name, color, type and age. The code also has setters and getters (accessors). At the end the __str__( )
method can print a simple message about this pet’s name
, age
, type
and color
.
Cat
is subclass of Pet
.
Cat
class constructor accepts only name, color
and age
, it’s type
is fixed to be 'Cat'
. The new constructor overrides the Pet
constructor.
Cat
also overrides the setter setType( )
. If someone tries to change the Cat
type, he will not be able to change it, instead he will get a message “…refuses to change type, it will always be a cat in this life!”
.
'Cat' also overrides setAge()
method, it puts a limit on the age to be 1<age<30 (in years).
Let's use Pet
and Cat
in an application:
Ex. 12.1-2 test_PetCat.py
Pet
and Cat
classes are all saved in one file named PetCat.py
, to use them we need to import PetCat
module.
# test PetCat
>>> import PetCat # or use: from PetCat import Pet, Cat
>>> c = Cat('Sassy', 'white', 3)>
>>> print(c) # will invoke the `__str__()` inherited from parent class `Pet`
Sassy is a white cat aged 3.
>>>
>>> c.setAge(0.5) # not in the range defined in the override `setAge()` method
>>> c.getAge() # age not changed means the override setter is working
3 years # inherited getAge() is working
>>> c.setType('dog') # the override setter is in action
Sassy refuses to change type, it will always be a cat in this life.
>>> c.setName('Pussy') # inherited setter from Pet class
>>> print (c)
Pussy is a white cat aged 3.
>>>
Next, let's make a subclass of Cat
named Kitten
, see if Kitten
inherits anything from Pet
. (What's your guess?)
Ex. 12.1-3 Kitten.py
# Kitten.py subclass of Cat
from PetCat import Pet, Cat
class Kitten( Cat ):
"""Kitten is subclass of Cat, which is a subclass of Pet.
Kitten's age is usually from 0 to 12 months."""
def setAge(self, a):
if 0<a<12:
self.age = a
def getAge(self)
return ' {0} months'.format(self.age)
def __str__(self):
return ( '{0} is a {1} months old {2} Kitten.'.format(self.name, self.age, self.color) )
def say (self ):
print ( '{0} says Meow, Meow, Meow! Milk please!'.format (self.name) )
>>> k = Kitten( 'Tussy', 'yellow', 10 )
>>> print (k)
Tussy is a 10 months old yellow kitten.
>>> k.setAge(8)
>>> print ( k.getAge() )
8 months
>>> k.say()
tussy says Meow, Meow, Meow! Milk please!
>>>
Kitten
is subclass of Cat
, so it inherits Cat
and Pet
.
Kitten
class inherits Cat
constructor. But it overrides the setter setAge()
, it puts a limit on age to be 0<age<12
(in months). And Kitten
overrides the getter getAge()
in Pet
so to return a corresponding message , age in months.
Kitten
also overrides the__str__()
method (which is defined in Pet
) for a fitted display of it's objects.
To show that Kitten
inherits Pet
, we can try setName()
(which is also defined in Pet
) see if it works on Kitten
object.
'Kitten' has a new method say()
, if you call KittenObject.say()
, you will get like 'Tussy says Meow, Meow, Meow! Milk please! ' printed.