Lecture
16 Inheritance
1. Introduction
Every object-oriented programming language would not be worthy to look
at or use, if it weren't to support inheritance. Of course, Python
supports inheritance, it even supports multiple inheritance. Classes can
inherit from other classes. A class can inherit attributes and
behaviour methods from another class, called the superclass (or parent class). A class
which inherits from a superclass is called a subclass, also called child class. Superclasses are sometimes called ancestors as well. There exists a hierarchy
relationship between classes. It's similar to relationships or categorizations
that we know from real life. Think about vehicles, for example. Bikes,
cars, buses and trucks are vehicles. pick-ups, vans, sports cars,
convertibles and estate cars are all cars and by being cars they are
vehicles as well. We could implement a vehicle class in Python, which
might have methods like accelerate and brake. Cars, Buses and Trucks
and Bikes can be implemented as subclasses which will inherit these
methods from vehicle.
The syntax for a
subclass definition looks like this:
Of course, usually we will have an indented block with the class
attributes and methods instead of merely a pass statement. The name
BaseClassName must be defined in a scope containing the derived class
definition. With all this said, we can implement our Person and
Employee class:
This is a good example:
The object 'y' inherited the methods from class 'Person' (which makes
sense since an employee is also a person and has names), so it doesn't
have to have the attibutes claimed in the class 'Person' claimed in its
class 'Employee'.
The __init__ method of our Employee class explicitly invokes the
__init__method of the Person class. We could have used super instead.
super().__init__(first, last) is automatically replaced by a call to
the superclasses method, in this case __init__:
Notes that the 'self'
argument doesn't exist in 'super().__init__(first, last)'.
Please note that we used super() without arguments. This is only
possible in Python3. We could have written "super(Employee,
self).__init__(first, last, age)" which still works in Python3 and is
compatible with Python2.
2. Overloading and
overriding
Instead of using the methods "Name" and "GetEmployee" in our previous
example, it might have been better to put this functionality into the
"__str__" method. In doing so, we gain a lot, especially a cleaner
design. We have a string casting for our classes and we can simply
print out instances. Let's start with a __str__ method in Person:
Now, let's look at a code that was created to reach the same result but
failed. Can you tell why it is not working?
One last note: The following doesn't work:
The Employee class
inherits the 'self.firstname and the self.lastname' feature form the
Person class by 'super().__init__(fisrt, last)'. So in the child class,
you can selectively inherit some of the features in the parent class.
Which is great. You don't want to inherit the ones you don't need.
However, the
'super().__init__(first, last)' call doesn't have 'self' as one of the
arguments. Because you are calling the function __init__(self, first,
last) in the Person class. and this function already has self in there
and when you call it, you don't need to put 'self' in there. 'self' is
kind of a default argument, you only have it when you define the
function but you don't need it when you call this function.
The '__str__(self)'
function doesn't have all the firstname, lastname, stuffnumber
arguments. Why?
The '__str()' function is
called when you have 'print()' called at the end of the script (outside
of the class and function). If you print the entire object as
'print(freshMan)', then the argument 'freshMan' includes all the
fisrtname, lastname, and stuffnumber in it, so including all these
arguments in this call is redundant.
We have overridden the method __str__ from Person in Employee. By the
way, we have overridden __init__ also. Method overriding is an
object-oriented programming feature that allows a subclass to provide a
different implementation of a method that is already defined by its
superclass or by one of its superclasses. The implementation in the
subclass overrides the implementation of the superclass by providing a
method with the same name, same parameters or signature, and same
return type as the method of the parent class.
3. The Car example:
Let's make the Car class first. We all know that the major attributes
of a car can be: make, model, year, and odometer. We didn't put the
odometer in the '__init__()' function since it is actually being
changed along the way. But I still created a 'self.odometer_reading =
0' in the __init__() function to assign an initial value to the
odometer. (it is a new car).
Then let's start making subclasses to this Car class:
Oops! Something is wrong. The '2016' in my 'ElectricCar("tesla", 'model
s", 2016)' is an int variable. However, in the 'get_descriptive_name()'
function, I didn't convert it into a string in order to be printed out
later. So simply force it to a str variable there and you will fix it.
Thank Goodness! Objective-oriented programming is so fun!!!!
Tasks:
1. According to the given structure of the code and the given results,
complete the following code and verify your results.
2. According
to the given structure of the code and the given results, complete the
following code and verify your results.
3. Complete the following code:
4. Complete the following code: