Hour 15. Employing Inheritance


What You’ll Learn in This Hour:

Image What subclasses are

Image What inheritance is

Image How to use inheritance in Python

Image Inheritance in scripts


In this hour, you will learn about subclasses and inheritance, including how to create subclasses and how to use inheritance in scripts. Inheritance is the next step in understanding object-oriented programming in Python.

Learning About the Class Problem

In Hour 14, “Exploring the World of Object-Oriented Programming,” you read about object-oriented programming, classes, and class module files. Even with object-oriented programming, problems related to duplication of object data attributes and methods still exist. This is called the “class problem.” This hour looks at the biological classification of animals and plants to help clarify the nature of the class problem.

Suppose you are creating a Python script for an insect scientist (entomologist). What makes an insect an insect? A very basic classification for an insect is that an animal must have the following in order to be considered an insect:

Image No vertebral column (backbone)

Image A chitinous exoskeleton (outside shell)

Image A three-part body (head, thorax, and abdomen)

Image Three pairs of jointed legs

Image Compound eyes

Image One pair of antennae

Using this information, you could create an insect object definition. It would include these characteristics as part of the object module.

But think about the ant. An ant is classified as part of the insect class because it has all the characteristics just listed. However, an ant also has these unique characteristics that not all other insects share:

Image A narrow abdomen where it joins the thorax (looks like a tiny waist)

Image At the narrow abdomen where it joins the thorax, a hump on top that is clearly separate from the rest of the abdomen

Image Elbowed antennae, with a long first segment

Thus, to create an object definition for an ant, you would need to duplicate all the insect characteristics that are put into the insect object definition. In addition, you must add the characteristics that are specific to ants.

However, there are more insects than just ants. For example, the honey bee is also an insect. It shares the first characteristic specific to an ant (narrow abdomen). Therefore, to create a honey bee object definition, you would need to duplicate the characteristics from the insect object definition, duplicate the first ant characteristic from the ant object definition file, and then add the honey bee’s unique characteristics. That is a lot of duplication!

The class problem is strongly demonstrated in the three object definitions we’ve just look at (insects, ants, and honey bees). And there are more insects besides honey bees and ants! To fix the inefficient duplication class problem, Python uses subclasses and inheritance.

Understanding Subclasses and Inheritance

A subclass is an object definition. It has all the data attributes and methods of another class but includes additional attributes and methods specific to itself. These additional data attributes and methods make a subclass a specific version of a class. For example, an ant is a specific version of an insect.

A class whose data attributes and methods are used by a subclass is called a superclass. Using the insect example, the superclass would be Insect, and the subclass would be Ant. An ant has all the characteristics of an insect, as well as a few of its own, which are specific to ants.


By the Way: Object Class Terms

A superclass, also called a base class, is a class used in an object definition of a subclass. A subclass, which has all the data attributes and methods of a base class, as well as a few of its own, is also called a derived class.


Subclasses have what is called an “is a” relationship to their base class. For example, an ant (subclass) is an insect (base class). A honey bee (subclass) is an insect (base class). These are some other examples of “is a” relationships:

Image A duck is a bird.

Image Python is a programming language.

Image A Raspberry Pi is a computer.

In order for a subclass object to gain the data attributes and methods of its base class, Python uses a process called inheritance. In Python, inheritance is more similar to inheriting genes from your biological parents than receiving a monetary inheritance.

Inheritance is the process by which a subclass may obtain a copy of the base class’s data attributes and methods to include in its object class definition. The subclass object then creates its own data attributes and methods in its object class definition, to make itself a specialized version of the base class.

The example of ants and insects can be used to demonstrate inheritance. To keep it simple, only characteristics (data attributes) are used. But you could use behavior (methods) here, too! An insect base class object definition would contain the following data attributes:

Image backbone='none'

Image exoskeleton='chitinous'

Image body='three-part'

Image jointed_leg_pairs=3

Image eyes='compound'

Image antennae_pair=1

The ant object class definition would inherit all six of these insect data attributes. The following three data attributes would be added to make the subclass (ant object) a specialized version of the base class (insect object):

Image abdomen_thorax_width='narrow'

Image abdomen_thorax_shape='humped'

Image antennae='elbowed'

The ant “is a” insect relationship would be maintained. Basically, the ant “inherits” the insect’s object definition. There is no need to create duplicate data attributes and methods in the ant’s object definition. Thus, the class problem is solved.

Using Inheritance in Python

So what does inheritance look like in Python? This is the basic syntax for inheritance in a class object definition:

class classname:
     base class data attributes
     base class mutator methods
     base class accessor methods
     class classname (base class name):
          subclass data attributes
          subclass mutator methods
          subclass accessor methods

Listing 15.1 shows a bird class object definition stored in the object module /home/pi/py3prog/birds.py. The Bird class is an overly simplified object definition for a bird. Notice that there are three immutable data attributes: feathers (line 7), bones (line 8), and eggs (line 9). The only mutable data attribute is sex (line 10) because a bird can be male, female, or unknown.

LISTING 15.1 Bird Object Definition File


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/birds.py
2: # Bird base class
3: #
4: class Bird:
5:     #Initialize Bird class data attributes
6:     def __init__(self, sex):
7:         self.__feathers = 'yes'     #Birds have feathers
8:         self.__bones = 'hollow'     #Bird bones are hollow
9:         self.__eggs = 'hard-shell'  #Bird eggs are hard-shell.
10:         self.__sex = sex            #Male, female, or unknown.
11:
12:     #Mutator methods for Bird data attributes
13:     def set_sex(self, sex):    #Male, female, or unknown.
14:         self.__sex = sex
15:
16:     #Accessor methods for Bird data attributes
17:     def get_feathers(self):
18:         return self.__feathers
19:
20:     def get_bones(self):
21:         return self.__bones
22:
23:     def get_eggs(self):
24:         return self.__eggs
25:
26:     def get_sex(self):
27:         return self.__sex
28: pi@raspberrypi ~ $


Also notice in Listing 15.1 that there is one mutator method (lines 12 through 14) for the Bird class, and there are four accessor methods (lines 16 through 27). There’s nothing too special here. Most of these items should look similar to the class definitions in Hour 14.

Creating a Subclass

To add a subclass to the Bird base class, a barn swallow (also known as a European swallow) was chosen. For simplicity’s sake, the BarnSwallow subclass is also overly simplified. Any ornithologist will recognize that there is much more to a barn swallow than is listed here!

To add the BarnSwallow subclass, the subclass must be declared using the class declaration, as shown here:

class BarnSwallow(Bird):

This class declaration allows you to define a subclass of BarnSwallow that inherits from its base class (Bird). Thus, the BarnSwallow subclass object definition inherits all the data attributes and methods from the Bird base class.

As with initializing a class, all the data attributes to be used in the BarnSwallow subclass are initialized. This includes both base class and subclass data items, as shown here:

def __init__(self, feathers, bones, eggs, sex,
             migratory, flock_size):

Within the initialization block, the __init__ method of the Bird base class is used to initialize the inherited data attributes feather, bones, eggs, and sex. This needs to be done for inheritance purposes. You initialize the data attributes like this:

Bird.__init__(self, feathers, bones, eggs, sex)

Specialization of the BarnSwallow subclass can now begin. A barn swallow has the following specialized data attributes. One data attribute is immutable (migratory) and one is mutable (flock_size):

Image migratorySet to yes because a barn swallow is known for its large migratory range.

Image flock_sizeIndicates the number of birds seen in one sighting.

(Remember that this is an overly simplified example. A real barn swallow would have many more data attributes.)

These specialized data attributes are set using the following Python statements.

self.__migratory = 'yes'
self.__flock_size = flock_size

Since the first data attribute for the BarnSwallow subclass is immutable, the only mutator method needed is for flock_size. This is set as follows:

def set_flock_size(self,flock_size):
     self.__flock_size = flock_size

Finally, in the BarnSwallow subclass object definition, the accessor methods must be declared for the subclass data attributes. They are shown here:

def get_migratory(self):
     return self.__migratory
def get_flock_size(self, flock_size):
     return self.__flock_size

Once all the parts of the object definition have been determined, you can add the subclass to an object module file.

Adding a Subclass to an Object Module File

The BarnSwallow subclass object definition can be stored in the same module file as the Bird base class (see Listing 15.2).

LISTING 15.2 The BarnSwallow Subclass in the Bird Object File


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/birds.py
2: # Bird base class
3: #
4: class Bird:
5:     #Initialize Bird class data attributes
6:     def __init__(self, sex):
7: ...
8: #
9: # Barn Swallow subclass (base class: Bird)
10: #
11: class BarnSwallow(Bird):
12:
13:     #Initialize Barn Swallow data attributes & obtain Bird inheritance.
14:     def __init__(self, sex, flock_size):
15:
16:         #Obtain base class data attributes & methods (inheritance)
17:         Bird.__init__(self, sex)
18:
19:         #Initialize subclass data attributes
20:         self.__migratory = 'yes'        #Migratory bird.
21:         self.__flock_size = flock_size  #How many in flock.
22:
23:
24:     #Mutator methods for Barn Swallow data attributes
25:     def set_flock_size(self,flock_size):  #No. of birds in sighting
26:         self.__flock_size = flock_size
27:
28:     #Accessor methods for Barn Swallow data attributes
29:     def get_migratory(self):
30:         return self.__migratory
31:     def get_flock_size(self):
32:         return self.__flock_size
33: pi@raspberrypi ~ $


You can see a partial listing of the Bird base class object definition file on lines 2 through 7 of Listing 15.2. The BarnSwallow subclass object definition is on lines 8 through 32 of the birds.py object module file.


Watch Out!: Proper Indentation

Remember that you need to make sure you do the indentation properly for an object module file! If you do not indent object module blocks properly, Python gives you an error message, indicating that it cannot find a method or data attribute.


Inheritance allows you to use a subclass along with its base class in a module file. However, you are not limited to just one subclass in an object module file.

Adding Additional Subclasses

You can add additional subclass object definitions to an object module file. For example, the South African cliff swallow is very similar to a barn swallow, but it is non-migratory.

Listing 15.3 adds the SouthAfricanCliffSwallow subclass. Again, it is an oversimplified version of a bird. However, you can see that the subclass object definition has its own place within the object module file. You could list every subclass of bird that exists in the file birds.py, if you wanted to.

LISTING 15.3 The CliffSwallow Subclass in the Bird Object File


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/birds.py
2: # Bird base class
3: #
4: class Bird:
5:     #Initialize Bird class data attributes
6:     def __init__(self, sex):
7: ...
8:
9: #
10: # Barn Swallow subclass (base class: Bird)
11: #
12: class BarnSwallow(Bird):
13:
14:     #Initialize Barn Swallow data attributes & obtain Bird inheritance.
15:     def __init__(self, sex, flock_size):
16: ...
17: #
18: # South Africa Cliff Swallow subclass (base class: Bird)
19: #
20: class SouthAfricaCliffSwallow(Bird):
21:
22:     #Initialize Cliff Swallow data attributes & obtain Bird inheritance.
23:     def __init__(self, sex, flock_size):
24:
25:         #Obtain base class data attributes & methods (inheritance)
26:         Bird.__init__(self, sex)
27:
28:         #Initialize subclass data attributes
29:         self.__migratory = 'no'         #Non-migratory bird.
30:         self.__flock_size = flock_size  #How many in flock.
31:
32:
33:     #Mutator methods for Cliff Swallow data attributes
34:     def set_flock_size(self,flock_size):  #No. of birds in sighting
35:         self.__flock_size = flock_size
36:
37:     #Accessor methods for Cliff Swallow data attributes
38:     def get_migratory(self):
39:         return self.__migratory
40:     def get_flock_size(self):
41:         return self.__flock_size
42: pi@raspberrypi ~ $


Remember that modularity is important when you’re creating any program, including Python scripts. Thus, keeping all the bird subclasses in the same file as the Bird base class is not a good idea.

Putting a Subclass in Its Own Object Module File

For better modularity, you can store a base class in one object module file and store each subclass in its own module file. In Listing 15.4, you can see the modified /home/pi/py3prog/birds.py object module file. It does not include the BarnSwallow or SouthAfricanCliffSwallow subclass.

LISTING 15.4 A Bird Base Class Object File


pi@raspberrypi ~ $ cat /home/pi/py3prog/birds.py
# Bird base class
#
class Bird:
    #Initialize Bird class data attributes
    def __init__(self, sex):
...
    def get_sex(self):
        return self.__sex
pi@raspberrypi ~ $


To put a subclass in its own object module file, you need to add an import Python statement to the file, as shown in Listing 15.5. Here the Bird base class is imported before the BarnSwallow subclass is defined.

LISTING 15.5 The BarnSwallow Subclass Object File


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/barnswallow.py
2: #
3: # BarnSwallow subclass (base class: Bird)
4: #
5: from birds import Bird    #import Bird base class
6:
7: class BarnSwallow(Bird):
8:
9:     #Initialize Barn Swallow data attributes & obtain Bird inheritance.
10:     def __init__(self, sex, flock_size):
11:
12:         #Obtain base class data attributes & methods (inheritance)
13:         Bird.__init__(self, sex)
14:
15:         #Initialize subclass data attributes
16:         self.__migratory = 'yes'        #Migratory bird.
17:         self.__flock_size = flock_size  #How many in flock.
18:
19:
20:     #Mutator methods for Barn Swallow data attributes
21:     def set_flock_size(self, flock_size):  #No. of birds in sighting
22:            self.__flock_size = flock_size
23:
24:     #Accessor methods for Barn Swallow data attributes
25:     def get_migratory(self):
26:         return self.__migratory
27:     def get_flock_size(self):
28:         return self.__flock_size
29: pi@raspberrypi ~ $


You can see in Listing 15.5 that the Bird base class is imported on line 5. Notice that the import statement uses the from module_file_name import object_def format. It does so because the module file name is bird.py and the object definition is called Bird. After it is imported, the BarnSwallow subclass is defined on lines 7 through 28.

Once you have your object module files created—one containing the base class and others containing all the necessary subclasses—the next step is to use these files in Python scripts.

Using Inheritance in Python Scripts

Using inheritance in a Python script is really not much different from using regular base class objects in a script. Both the BarnSwallow subclass and the SouthAfricanCliffSwallow subclass are used in script1501.py, along with their Bird base class. The script, as shown in Listing 15.6, simply goes through the objects and displays the immutable settings of each.

LISTING 15.6 Python Statements in script1501.py


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/script1501.py
2: # script1501.py - Display Bird immutable data via Accessors
3: # Written by Blum and Bresnahan
4: #
5: ############ Import Modules ##################
6: #
7: # Birds object file
8: from birds import Bird
9: #
10: # Barn Swallow object file
11: from barnswallow import BarnSwallow
12: #
13: # South Africa Cliff Swallow object file
14: from sacliffswallow import SouthAfricaCliffSwallow
15: #
16: def main ():
17:      ###### Create Variables & Object Instances ###
18:      #
19:      sex='unknown'  #Male, female, or unknown
20:      flock_size='0'
21:      #
22:      bird=Bird(sex)
23:      barn_swallow=BarnSwallow(sex,flock_size)
24:      sa_cliff_swallow=SouthAfricaCliffSwallow(sex,flock_size)
25:      #
26:      ########## Show Bird Characteristics ########
27:      #
28:      print("A bird has",end=' ')
29:      if bird.get_feathers() == 'yes':
30:           print("feathers,", end=' ')
31:      print("bones that are", bird.get_bones(), end=' ')
32:      print("and", bird.get_eggs(), "eggs.")
33:      #
34:      ###### Show Barn Swallow Characteristics #####
35:      #
36:      print()
37:      print("A barn swallow is a bird that", end=' ')
38:      if barn_swallow.get_migratory() == 'yes':
39:           print("is migratory.")
40:      else:
41:           print("is not migratory.")
42:      #
43:      ######## Show Cliff Swallow Characteristics ######
44:      #
45:      print()
46:      print("A cliff swallow is a bird that", end=' ')
47:      if sa_cliff_swallow.get_migratory() == 'yes':
48:           print("is migratory.")
49:      else:
50:           print("is not migratory.")
51: #########################################################
52: #
53: ########## Call the main function #######################
54: main()


In the script, the object module files are imported before the start of the main function declaration on lines 7 through 14. The variables sex and flock_size are to be used as arguments and thus are set to 'unknown' and 0, respectively, on lines 19 and 20.

In Listing 15.6, the object instances themselves are declared on lines 22 through 24. Finally, the accessors for each object are used to obtain the immutable values of each object class. They are printed to the screen on line 28 through line 50.

Listing 15.7 shows script1501.py in action. Both the base class and each subclass’s immutable values are displayed.

LISTING 15.7 Output of script1501.py


pi@raspberrypi ~ $ python3 /home/pi/py3prog/script1501.py
A bird has feathers, bones that are hollow and hard-shell eggs.

A barn swallow is a bird that is migratory.

A cliff swallow is a bird that is not migratory.
pi@raspberrypi ~ $


As you can see, the script runs fine. Both the BarnSwallow object and the SouthAfricaCliffSwallow object are able to inherit data attributes and methods within the script from the Bird object with no problems.

Many ornithology organizations around the world—such as Cornel’s Great Backyard Bird Count, at www.birdsource.org/gbbc/—seek bird-sighting information. The script1501.py script was modified to include sighting information and renamed script1502.py.

Listing 15.8 shows the script1502.py script. It now includes methods to obtain flock size information.

LISTING 15.8 Python Statements in script1501.py


1: pi@raspberrypi ~ $ cat /home/pi/py3prog/script1502.py
2: # script1502.py - Record a Swallow Sighting
3: # Written by Blum and Bresnahan
4: #
5: ############ Import Modules  ##################
6: #
7: # Birds object file
8: from birds import Bird
9: #
10: # Barn Swallow object file
11: from barnswallow import BarnSwallow
12: #
13: # South Africa Cliff Swallow object file
14: from sacliffswallow import SouthAfricaCliffSwallow
15: #
16: # Import Date Time function
17: import datetime
18: #
19: ################################################
20: def main ():     #Mainline
21:      ###### Create Variables & Object Instances ###
22:      #
23:       flock_size='0'      #Number of birds sighted
24:       sex='unknown'       #Male, female, or unknown
25:       species=''          #Barn or Cliff Swallow Object
26:       #
27:       barn_swallow=BarnSwallow(sex,flock_size)
28:       sa_cliff_swallow=SouthAfricaCliffSwallow(sex,flock_size)
29:       #
30:       ###### Instructions for Script User #########
31:       print()
32:       print("The following characteristics are listed")
33:       print("in order to help you determine what swallow")
34:       print("you have sighted.")
35:       print()
36:       #
37:       ###### Show Barn Swallow Characteristics #####
38:       #
39:       print("A barn swallow is a bird that", end=' ')
40:       if barn_swallow.get_migratory() == 'yes':
41:               print("is migratory.")
42:       else:
43:               print("is not migratory.")
44:       #
45:       ######## Show Cliff Swallow Characteristics ######
46:       #
47:       print("A cliff swallow is a bird that", end=' ')
48:       if sa_cliff_swallow.get_migratory() == 'yes':
49:               print("is migratory.")
50:       else:
51:               print("is not migratory.")
52:       #
53:       ######## Obtain Swallow Sighted #################
54:       print()
55:       print("Which did you see?")
56:       print("European/Barn Swallow    - 1")
57:       print("African Cliff Swallow    - 2")
58:       species = input("Type number & press Enter: ")
59:       print()
60:       #
61:       ######## Obtain Flock Size #################
62:       #
63:       flock_size=int(input("Approximately, how many did you see? "))
64:       #
65:       ###### Mutate Sighted Birds' Flock Size ####
66:       #
67:       if species == '1':
68:            barn_swallow.set_flock_size(flock_size)
69:       else:
70:            sa_cliff_swallow.set_flock_size(flock_size)
71:       #
72:       ###### Display Sighting Data ################
73:       print()
74:       print("Thank you.")
75:       print("The following data will be forwarded to")
76:       print("the Great Backyard Bird Count.")
77:       print("www.birdsource.org/gbbc")
78:       #
79:       print()
80:       print("Sighting on ", datetime.date.today())
81:       if species == '1':
82:            print("Species: European/Barn Swallow")
83:            print("Flock Size: ", barn_swallow.get_flock_size())
84:            print("Sex: ", barn_swallow.get_sex())
85:       else:
86:            print("Species: South Africa Cliff Swallow")
87:            print("Flock Size: ", sa_cliff_swallow.get_flock_size())
88:            print("Sex: ", sa_cliff_swallow.get_sex())
89: #
90: #########################################################
91: #
92: ########## Call the main function #######################
93: main()
94: pi@raspberrypi ~


Notice in lines 84 and 88 of Listing 15.8 that the accessor methods are used to obtain the bird’s sex. .get_sex is an accessor method set in the Bird base class (refer to Listing 15.1, lines 26 and 27). Both the subclasses BarnSwallow and SouthAfricaCliffSwallow inherited methods from Bird. Thus, they are able to access the data by using the inherited .get_sex accessor method. This is called polymorphism.


Did You Know: Polymorphism

Polymorphism is the ability of subclasses to have methods with the same name as methods in their base class. This is sometimes called overriding a method. You can still access each class’s method, by using either base_class.method or subclass.method.


Listing 15.9 shows Python interpreting script1502.py. When the script is run, the subclasses inherit data attributes and methods with no problems.

LISTING 15.9 script1502.py Interpreted


pi@raspberrypi ~ $ python3 /home/pi/py3prog/script1502.py

The following characteristics are listed
in order to help you determine what swallow
you have sighted.

A barn swallow is a bird that is migratory.
A cliff swallow is a bird that is not migratory.

Which did you see?
European/Barn Swallow    - 1
African Cliff Swallow    - 2
Type number & press Enter: 1

Approximately, how many did you see? 7

Thank you.
The following data will be forwarded to
the Great Backyard Bird Count.
www.birdsource.org/gbbc

Sighting on       2013-11-06
Species:      European/Barn Swallow
Flock Size:      7
Sex:           unknown
pi@raspberrypi ~ $


Again, for simplicity, the data gathered here is overly simplified. However, to aid in your understanding of inheritance, subclasses, and object module files, you are going to improve it!


By the Way: Make It Easy

Instead of doing all this typing, you can download script1502.py from informit.com/register. After downloading the script, simply use it instead of creating the new script1503.py.


6. Make sure you have entered the code into the nano text editor window, as shown in Listing 15.6. Make any corrections needed.

7. Write out the information from the text editor to the script by pressing Ctrl+O. The script file name shows along with the prompt File name to write. Press Enter to write out the contents to the script1503.py script.

8. Exit the nano text editor by pressing Ctrl+X.

9. At the command-line prompt, type nano py3prog/birds.py and press Enter. This command puts you into the nano text editor and creates the file py3prog/birds.py.

10. Type all the information from birds.py in Listing 15.4 into the nano editor window. You are creating the Birds base class object file that is needed for the Python script.


By the Way: Continue to Make It Easy

Instead of doing all this typing, you can download all three files—birds.py, barnswallow.py, and sacliffswallow.py—from informit.com/register. After downloading these object module files, you can skip over the steps to create them!


11. Make sure you have entered the statements into the nano text editor window, as shown in Listing 15.4. Make any corrections needed.

12. Write out the information from the text editor to the file by pressing Ctrl+O. The file name shows along with the prompt File name to write. Press Enter to write out the contents to the birds.py object file.

13. Exit the nano text editor by pressing Ctrl+X.

14. At the command-line prompt, type nano py3prog/barnswallow.py and press Enter. The command puts you into the nano text editor and creates the file py3prog/barnswallow.py.

15. Type all the information from barnswallow.py in Listing 15.5 into the nano editor window. You are creating the BarnSwallow subclass object file that is needed for the Python script.

16. Make sure you have entered the statements into the nano text editor window, as shown in Listing 15.5. Make any corrections needed.

17. Write out the information from the text editor to the file by pressing Ctrl+O. The file name shows along with the prompt File name to write. Press Enter to write out the contents to the barnswallow.py object file.

18. Exit the nano text editor by pressing Ctrl+X.

19. Hang in there! You are getting close! At the command-line prompt, type nano py3prog/sacliffswallow.py and press Enter. The command puts you into the nano text editor and creates the file py3prog/sacliffswallow.py.

20. In the nano text editor window, type the information from lines 17–29 in the birds.py file in Listing 15.3 (the comment lines).

21. Now type the following into the nano editor window:

from birds import Bird    #import Bird base class

22. Finish the SouthAfricaCliffSwallow subclass object file that needed for the Python script by typing in the Python statements from lines 20 through 41 in Listing 15.3.

23. Make sure you have entered the statements into the nano text editor window as shown in Listing 15.3, along with the additional import statement. Make any corrections needed.

24. Write out the information from the text editor to the file by pressing Ctrl+O. The file name shows along with the prompt File name to write. Press Enter to write out the contents to the sacliffswallow.py object file.

25. Exit the nano text editor by pressing Ctrl+X.

26. Before making the improvements, make sure all is well with your code by typing python3 py3prog/script1503.py. If you get any errors, double-check the four files for any typos and make corrections as needed. Next you will begin the improvements.

27. Create a base class called Sighting and subclass called BirdSighting. For simplicity’s sake, you can put them both in one module file. Type nano py3prog/sightings.py and press Enter. Python puts you into the nano text editor and creates the object module file py3prog/sightings.py.

28. Type the following code into the nano editor window:

# Sightings base class
#
class Sighting:
    #Initialize Sighting class data attributes
    def __init__(self, sight_location, sight_date):
        self.__sight_location = sight_location  #Location of sighting
        self.__sight_date = sight_date          #Date of sighting

    #Mutator methods for Sighting data attributes
    def set_sight_location(self, sight_location):
        self.__sight_location = sight_location

    def set_sight_date(self, sight_date):
        self.__sight_date = sight_date

    #Accessor methods for Sighting data attributes
    def get_sight_location(self):
        return self.__sight_location

    def get_sight_date(self):
        return self.__sight_date
#
# Bird Sighting subclass (base class: Sighting)
#
class BirdSighting(Sighting):

    #Initialize Bird Sighting data attributes & obtain Bird inheritance.
    def __init__(self, sight_location, sight_date,
                 bird_species, flock_size):

        #Obtain base class data attributes & methods (inheritance)
        Sighting.__init__(self, sight_location, sight_date)

        #Initialize subclass data attributes
        self.__bird_species = bird_species #Bird type
        self.__flock_size = flock_size     #How many in flock.


    #Mutator methods for Bird Sighting data attributes
    def set_bird_species(self,bird_species):
        self.__bird_species = bird_species

    def set_flock_size(self,flock_size):
        self.__flock_size = flock_size

    #Accessor methods for Bird Sighting data attributes
    def get_bird_species(self):
        return self.__bird_species
    def get_flock_size(self):
        return self.__flock_size

29. Write out the information from the text editor to the file by pressing Ctrl+O. The file name shows along with the prompt File name to write. Press Enter to write out the contents to the sightings.py object file.

30. Exit the nano text editor by pressing Ctrl+X.

31. To modify the script to use these two objects, at the command-line prompt, type nano py3prog/script1503.py and press Enter.

32. For the first change, in the Import Modules section of the script, under the import of the SouthAfricanCliffSwallow object file, insert the following lines (which import the new object files into the script):

# Sightings object file
from sightings import Sighting
#
# Birds sightings object file
from sightings import BirdSighting

33. For the second change, in the Create Variables & Object Instances section of the script, under the creation of both the barn and cliff swallow object instances, insert the following lines, properly indented:

location='unknown'     #Location of sighting
date='unknown'         #Date of sighting
#
bird_sighting=BirdSighting(location,date,species,flock_size)

34. For the third change, delete both the sections Obtain Flock Size and Mutate Sighted Birds' Flock Size, along with their Python statements:

######## Obtain Flock Size #################
     #
     flock_size=int(input("Approximately, how many did you see? "))
     #
     ###### Mutate Sighted Birds' Flock Size ####
     #
     if species == '1':
          barn_swallow.set_flock_size(flock_size)
     else:
          sa_cliff_swallow.set_flock_size(flock_size)
     #

35. In place of what you just deleted, add the following:

######## Obtain Sighting Information #################
     #
     location=input("Where did you see the birds? ")
     print()
     flock_size=int(input("Approximately, how many did you see? "))
     #
     ###### Mutate Sighted Birds' Information ####
     #
     bird_sighting.set_sight_location(location)
     bird_sighting.set_sight_date(datetime.date.today())
     if species == '1':   #CHANGE
          bird_sighting.set_bird_species('barn swallow')
     else:
          bird_sighting.set_bird_species('SA cliff swallow')
     bird_sighting.set_flock_size(flock_size)
     #

(Notice that the mutators, such as .set_sight_date, are now all from the bird_sighting subclass.)

36. For the fourth change, in the section Display Sighting Data, delete the following Python statements:

print("Sighting on ", datetime.date.today())
     if species == '1':
          print("Species: European/Barn Swallow")
          print("Flock Size: ", barn_swallow.get_flock_size())
          print("Sex: ", barn_swallow.get_sex())
     else:
          print("Species: South Africa Cliff Swallow")
          print("Flock Size: ", sa_cliff_swallow.get_flock_size())
          print("Sex: ", sa_cliff_swallow.get_sex())

37. In place of what you just deleted, add the following:

print("Sighting Date: ", bird_sighting.get_sight_date())
print("Location: ", bird_sighting.get_sight_location())
if species == '1':
     print("Species: European/Barn Swallow")
else:
     print("Species: South Africa Cliff Swallow")
print("Flock Size: ", bird_sighting.get_flock_size())

(Notice that the accessors, such as .get_flock_size, are now all from the bird_sighting subclass.)

38. Review the four major changes you just made to script1503.py to ensure that there are no typos and that the indentation is correct.

39. Write out the information from the text editor to the script by pressing Ctrl+O. The script file name shows along with the prompt File name to write. Press Enter to write out the contents to the script1503.py script.

40. Exit the nano text editor by pressing Ctrl+X. All your work is about to pay off!

41. To test your modifications to the script, at the command-line prompt, type python3 /home/pi/py3prog/script1503.py and press Enter. Answer the script questions as you please. If there are no problems with your script or object definition file, the output will look similar to Listing 15.10.

LISTING 15.10 The script1503.py Interpreted


pi@raspberrypi ~ $ python3 /home/pi/py3prog/script1503.py

The following characteristics are listed
in order to help you determine what swallow
you have sighted.

A barn swallow is a bird that is migratory.
A cliff swallow is a bird that is not migratory.

Which did you see?
European/Barn Swallow    - 1
African Cliff Swallow    - 2
Type number & press Enter: 1

Where did you see the birds? Indianapolis, Indiana, USA

Approximately, how many did you see? 21

Thank you.
The following data will be forwarded to
the Great Backyard Bird Count.
www.birdsource.org/gbbc

Sighting Date:      2013-11-06
Location:           Indianapolis, Indiana, USA
Species:            European/Barn Swallow
Flock Size:         21
pi@raspberrypi ~ $


Good job! You’ve done quite a bit of work here, but if you are like most other script writers, you probably already see several things to improve in this script. For instance, there are no checks on user-input data. The data should be output to a file, not just displayed to the screen. In addition, to make the data useful, the time of day should be recorded, and more bird species should be added. You can make all sorts of changes to this script!

Here is an idea to start. Start with script1503.py and try adding better bird descriptions to the swallow subclass object module files to aid in their species identification. Now that you know how to create subclasses using inheritance, you can get the script’s “ducks in a row.”

Summary

In this hour, you read about the class problem, Python subclasses, and the inheritance solution. You learned how to create an object subclass in the same object module file as the base class. Also, you learned how to create a subclass in its own object module file. Finally, you saw some practical examples of using the base classes and subclasses in a few Python scripts. In Hour 16, “Regular Expressions,” you will explore regular expressions.

Q&A

Q. What is the difference between an “is a” relationship and a “has a” relationship in Python?

A. An “is a” relationship exists between a subclass and its base class. For example, a barn swallow “is a” bird. A “has a” relationship exists between a class (a subclass or base class) and one of its data attributes or methods. For example, looking at the class definition of a bird, you can see from one of the data attribute statements that a bird “has a” feather.

Q. I added a subclass definition in a base class object file, and when I try to use one of the stated methods, Python tells me the method is not found. Why?

A. Most likely, you do not have the correct indentation in the class object file. Try re-creating the file within the IDLE 3 editor, which will give you some assistance creating the proper indentation. An even better solution would be to put the subclass in its own object file, using the IDLE 3 editor. Just be sure to include the proper import statements of the base class.

Q. Do I have to use subclasses?

A. No, there are no Python style police out there waiting to force you to use subclasses. However, good form dictates that you should use subclasses to avoid the duplication issues in the class problem.

Workshop

Quiz

1. A superclass is the same thing as a derived class. True or false?

2. What is it called when a subclass receives data attributes and methods from a base class?

3. Which Python statement correctly declares the subclass Ant of the base class Insect?

a. class Insect(Ant):

b. class Ant(Insect):

c. from Insect subclass Ant():

Answers

1. False. A superclass is also called a base class. A subclass, which inherits data attributes and methods of a base class, is also called a derived class because some of its attributes and methods are derived from the base class.

2. Inheritance is the term used when a subclass receives data attributes and methods from a base class.

3. Answer b is correct. To properly create the subclass Ant from the base class Insect, you use class Ant(Insect):.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.23.130.191