CS 1110 - Introduction to Programming

Starting Out with Python
Chapter 11, Inheritance

Objectives:

This lesson discusses chapter 11, to introduce concepts about inheritance. Objectives important to this lesson:

  1. Introduction to inheritance
  2. Polymorphism
Concepts:
Chapter 11

Introduction to Inheritance

Classes that are in a superclass-subclass relationship do not have to be identical. The chapter begins with an analogy. You probably know many types of bugs that are all members of the biological taxonomic Class insecta, or, insects. All instances of this class naturally have specific attributes: six legs with joints, bodies that have three major sections, compound eyes, and antennae. However, the next level of classification of animals separates them based on other attributes that are shared by all members of a particular group (their Order, if you are keeping track), but not shared by all insects. This means each Order of insects is specialized in some way that makes them different from each other, but they are all still insects.


The text uses this biological example to make a point. Each of the creatures in the image above are still insects, even though each has additional attributes, and possibly additional methods, that the others do not have. In terms of the book's logic, all of the insects above have the particular specialized characteristics of their subclasses (which make them butterflies, and wasps, and ants, and grasshoppers, and so on), but they all have the more general characteristics of their superclass, insects, as well.

In Python programming, a superclass has methods and attributes that are inherited by subclasses that are based on that superclass. The text continues with an example about motor vehicles. We are told we are making a program for a car dealership, one that sells cars, pickup trucks, and sport utility vehicles. In each case, the dealer wants to track at least four attributes about each vehicle:

  • make
  • model year
  • mileage
  • price

From that starting point, the dealer also wants to track specific information about each of the three types of vehicles:

  • for cars, we will track whether they have 2 or 4 doors
  • for pickups, we will track whether they are 2-wheel or 4-wheel drive
  • for SUVs, we will track the passenger capacity

There are more things a real dealership would track, but this is an example. The text observes that we could make a separate class for each type of vehicle, but this would be inefficient, since each type needs the four common attributes, as well as its own specific attribute. The author will show us a better way.

In example program 11-1, the text shows us a class description it calls Automobile. Instances of this class will have the standard accessors and mutators for each of the four named attributes, as well as the standard __init__ method. So far, so good. The class description is saved in a file called vehicles.py.

In example program 11-2, more lines are added to the vehicles.py file, showing us how to create a subclass. The code continues with a class definition for a class called Car. Car seems to take the Automobile class as an argument, Car(Automobile), but that is not quite what happens. This notation is meant to tells us that Car will be a type of Automobile, a subclass of Automobile. As all classes should, the Car class has an __init__ method. In this case, it expects arguments for self, for the four attributes of an Automobile, and for the new attribute of a Car, __doors. This module has two purposes. The first four arguments (and self) are passed to the __init__ method of the Automobile class, causing it to create the methods and attributes of an Automobile in the instance of a new car.

def __init__(self, make, model, mileage, price, doors):
    Automobile.__init__(self, make, model, mileage, price)
    self.__doors = doors

The second purpose of the __init__ method of Car is to create an attribute called __doors, and to assign the last argument it was passed to that attribute. This is done in the second line inside the the code block above.

Once the __init__ method of the superclass has run, all of the objects that method creates are now objects in the new instance of Car, and they can be addressed as such.In short, this is how you accomplish inheritance: you make an object that starts out being identical to objects made from the superclass, then you add the specialized methods and/or attributes that your subclass also needs.

Following the procedure, the author creates a definition for a Truck class, which has an __init__ method, which calls the __init__ method of the Automobile class to get the essential methods and attributes of that class. You should be able to predict what that __init__ method looks like:

def __init__(self, make, model, mileage, price, drive_type):
    Automobile.__init__(self, make, model, mileage, price)
    self.__drive_type = drive_type

It is very much like the last one, but it requires a different argument to supply a proper value to its specific attribute. If you have been following along, you should be able to guess what the __init__ method of the SUV class will look like:

def __init__(self, make, model, mileage, price, pass_cap):
    Automobile.__init__(self, make, model, mileage, price)
    self.__pass_cap = pass_cap


All these code changes are shown in example program 11-6. the text follows the code example with UML diagrams of the Automobile, Car, Truck, and SUB classes. Note that the Automobile diagram is shown on a line above the other three, and those three are connected to the Automobile diagram with an upward pointing arrow. This notation means that they are subclasses, which means we can assume that the attributes and methods shown in the superclass also exist in the subclasses.

The text walks through an example of creating a superclass for bank accounts, and subclasses for specific kinds of accounts. It goes through this part quickly, since it is just the same material again, but in a new example.


Polymorphism

The next section of the chapter is about polymorphism, which means many forms. This term means something new in superclass and subclass objects. The main idea is that you can rewrite a method in a subclass, which overrides the version of the method inherited from the superclass. It becomes possible to call either version of the method, depending on the class that it is called from.

The author points out that we have already done this. Each of the subclass examples we have examined has its own __init__ method. In a sense, that version overrides the __init__ method of the superclass by adding new code to it.

The chapter presents an example of a superclass called Mammal, and subclasses for Dog and Cat. Each class has a make_sound method, but the sound that is made is different for each of the classes. You can say that they have a common method, but the method takes a different form for each class. That is polymorphism.

The text introduces a new function called isinstance(). It is used like this:

isinstance(object_name, Class_name)

This function requires two arguments, the name of an object, and the name of a class. Its behavior is slightly more complicated than you might think. It returns True if the object in question is an instance of either the class that was named, or a subclass of the class that was named.

This function allows us to determine whether an object is a member of a particular class, or a subclass of that class. If it is, we can be confident in calling any known method of that class from within that object.

Assignments

Assignments for this chapter will be found in Blackboard. We will explore that in class.