Pages

Thursday, September 9, 2010

Inheritance


One of the major benefits of object oriented programming is reuse of code and one of the ways this is
achieved is through the inheritance mechanism. Inheritance can be best imagined as implementing a
type and subtype relationship between classes.
Suppose you want to write a program which has to keep track of the teachers and students in a college.
They have some common characteristics such as name, age and address. They also have specific characteristics
such as salary, courses and leaves for teachers and, marks and fees for students.
You can create two independent classes for each type and process them but adding a new common characteristic
would mean adding to both of these independent classes. This quickly becomes unwieldy.
A better way would be to create a common class called SchoolMember and then have the teacher and
student classes inherit from this class i.e. they will become sub-types of this type (class) and then we can
add specific characteristics to these sub-types.
There are many advantages to this approach. If we add/change any functionality in SchoolMember,
this is automatically reflected in the subtypes as well. For example, you can add a new ID card field for
both teachers and students by simply adding it to the SchoolMember class. However, changes in the subtypes
do not affect other subtypes. Another advantage is that if you can refer to a teacher or student object
as a SchoolMember object which could be useful in some situations such as counting of the number
of school members. This is called polymorphism where a sub-type can be substituted in any situation
where a parent type is expected i.e. the object can be treated as an instance of the parent class.
Also observe that we reuse the code of the parent class and we do not need to repeat it in the different
classes as we would have had to in case we had used independent classes.
The SchoolMember class in this situation is known as the base class or the superclass. The Teacher
and Student classes are called the derived classes or subclasses.
We will now see this example as a program.

Using Inheritance

Example 11.5. Using Inheritance
#!/usr/bin/python
# Filename: inherit.py
class SchoolMember:
'''Represents any school member.'''
def __init__(self, name, age):
self.name = name
self.age = age
print '(Initialized SchoolMember: %s)' % self.name
def tell(self):
'''Tell my details.'''
print 'Name:"%s" Age:"%s"' % (self.name, self.age),
class Teacher(SchoolMember):
'''Represents a teacher.'''
def __init__(self, name, age, salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
print '(Initialized Teacher: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Salary: "%d"' % self.salary
class Student(SchoolMember):
'''Represents a student.'''
def __init__(self, name, age, marks):
SchoolMember.__init__(self, name, age)
self.marks = marks
print '(Initialized Student: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Marks: "%d"' % self.marks
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
print # prints a blank line
members = [t, s]
for member in members:
member.tell() # works for both Teachers and Students


Output
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)
Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75"

How It Works
To use inheritance, we specify the base class names in a tuple following the class name in the class
definition. Next, we observe that the __init__ method of the base class is explicitly called using the
self variable so that we can initialize the base class part of the object. This is very important to remember
- Python does not automatically call the constructor of the base class, you have to explicitly call
it yourself.
We also observe that we can call methods of the base class by prefixing the class name to the method
call and then pass in the self variable along with any arguments.
Notice that we can treat instances of Teacher or Student as just instances of the SchoolMember
when we use the tell method of the SchoolMember class.
Also, observe that the tell method of the subtype is called and not the tell method of the School-
Member class. One way to understand this is that Python always starts looking for methods in the type,
which in this case it does. If it could not find the method, it starts looking at the methods belonging to its
base classes one by one in the order they are specified in the tuple in the class definition.
A note on terminology - if more than one class is listed in the inheritance tuple, then it is called multiple
inheritance.


Class and Object Variables


We have already discussed the functionality part of classes and objects, now we'll see the data part of it.
Actually, they are nothing but ordinary variables which are bound to the classes and objects namespaces
i.e. the names are valid within the context of these classes and objects only.
There are two types of fields - class variables and object variables which are classified depending on
whether the class or the object owns the variables respectively.
Class variables are shared in the sense that they are accessed by all objects (instances) of that class.
There is only copy of the class variable and when any one object makes a change to a class variable, the change is reflected in all the other instances as well.

Object variables are owned by each individual object/instance of the class. In this case, each object has
its own copy of the field i.e. they are not shared and are not related in any way to the field by the samen
name in a different instance of the same class. An example will make this easy to understand.

Using Class and Object Variables

Example 11.4. Using Class and Object Variables
#!/usr/bin/python
# Filename: objvar.py
class Person:
'''Represents a person.'''
population = 0
def __init__(self, name):
'''Initializes the person's data.'''
self.name = name
print '(Initializing %s)' % self.name
# When this person is created, he/she
# adds to the population
Person.population += 1
def __del__(self):
'''I am dying.'''
print '%s says bye.' % self.name
Person.population -= 1
if Person.population == 0:
print 'I am the last one.'
else:
print 'There are still %d people left.' % Person.population
def sayHi(self):
'''Greeting by the person.
Really, that's all it does.'''
print 'Hi, my name is %s.' % self.name
def howMany(self):
'''Prints the current population.'''
if Person.population == 1:
print 'I am the only person here.'
else:
print 'We have %d persons here.' % Person.population
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
swaroop.sayHi()
swaroop.howMany()

Output
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.

How It Works
This is a long example but helps demonstrate the nature of class and object variables. Here, population
belongs to the Person class and hence is a class variable. The name variable belongs to the object
(it is assigned using self) and hence is an object variable.
Thus, we refer to the population class variable as Person.population and not as
self.population. Note that an object variable with the same name as a class variable will hide the
class variable! We refer to the object variable name using self.name notation in the methods of that
object. Remember this simple difference between class and object variables.
Observe that the __init__ method is used to initialize the Person instance with a name. In this
method, we increase the population count by 1 since we have one more person being added. Also
observe that the values of self.name is specific to each object which indicates the nature of object
variables.
Remember, that you must refer to the variables and methods of the same object using the self variable
only. This is called an attribute reference.
In this program, we also see the use of docstrings for classes as well as methods. We can access the
class docstring at runtime using Person.__doc__ and the method docstring as Person.
sayHi.__doc__
Just like the __init__ method, there is another special method __del__ which is called when an object
is going to die i.e. it is no longer being used and is being returned to the system for reusing that
piece of memory. In this method, we simply decrease the Person.population count by 1.
The __del__ method is run when the object is no longer in use and there is no guarantee when that
method will be run. If you want to explicitly do this, you just have to use the del statement which we
have used in previous examples.
Note for C++/Java/C# Programmers

All class members (including the data members) are public and all the methods are virtual in
Python.
One exception: If you use data members with names using the double underscore prefix such as
__privatevar, Python uses name-mangling to effectively make it a private variable.
Thus, the convention followed is that any variable that is to be used only within the class or object
should begin with an underscore and all other names are public and can be used by other
classes/objects. Remember that this is only a convention and is not enforced by Python (except
for the double underscore prefix).
Also, note that the __del__ method is analogous to the concept of a destructor.




The __init__ method


There are many method names which have special significance in Python classes. We will see the significance
of the __init__ method now.
The __init__ method is run as soon as an object of a class is instantiated. The method is useful to do
any initialization you want to do with your object. Notice the double underscore both in the beginning
and at the end in the name.

Using the __init__ method

Example 11.3. Using the __init__ method
#!/usr/bin/python
# Filename: class_init.py
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
p = Person('Swaroop')
p.sayHi()
# This short example can also be written as Person('Swaroop').sayHi()


Output
$ python class_init.py
Hello, my name is Swaroop


How It Works
Here, we define the __init__ method as taking a parameter name (along with the usual self). Here,
we just create a new field also called name. Notice these are two different variables even though they
have the same name. The dotted notation allows us to differentiate between them.
Most importantly, notice that we do not explicitly call the __init__ method but pass the arguments in
the parentheses following the class name when creating a new instance of the class. This is the special
significance of this method.
Now, we are able to use the self.name field in our methods which is demonstrated in the sayHi
method.
Note for C++/Java/C# Programmers
The __init__ method is analogous to a constructor in C++, C# or Java.

object Methods

We have already discussed that classes/objects can have methods just like functions except that we have
an extra self variable. We will now see an example.

Using Object Methds

Example 11.2. Using Object Methods
#!/usr/bin/python
# Filename: method.py
class Person:
def sayHi(self):
print 'Hello, how are you?'
p = Person()
p.sayHi()
# This short example can also be written as Person().sayHi()

Output
$ python method.py
Hello, how are you?


How It Works
Here we see the self in action. Notice that the sayHi method takes no parameters but still has the
self in the function definition.

Classes

The simplest class possible is shown in the following example.

Creating a Class

Example 11.1. Creating a Class
#!/usr/bin/python
# Filename: simplestclass.py
class Person:
pass # An empty block
p = Person()
print p


Output
$ python simplestclass.py
<__main__.Person instance at 0xf6fcb18c>

How It Works
We create a new class using the class statement followed by the name of the class. This follows an indented
block of statements which form the body of the class. In this case, we have an empty block which
is indicated using the pass statement.
Next, we create an object/instance of this class using the name of the class followed by a pair of parentheses.
(We will learn more about instantiation in the next section). For our verification, we confirm the
type of the variable by simply printing it. It tells us that we have an instance of the Person class in the
__main__ module.
Notice that the address of the computer memory where your object is stored is also printed. The address
will have a different value on your computer since Python can store the object wherever it finds space.

Object-Oriented Programming Introduction


In all our programs till now, we have designed our program around functions or blocks of statements
which manipulate data. This is called the procedure-oriented way of programming. There is another way
of organizing your program which is to combine data and functionality and wrap it inside what is called
an object. This is called the object oriented programming paradigm. Most of the time you can use procedural
programming but sometimes when you want to write large programs or have a solution that is
better suited to it, you can use object oriented programming techniques.
Classes and objects are the two main aspecs of object oriented programming. A class creates a new type
where objects are instances of the class. An analogy is that you can have variables of type int which
translates to saying that variables that store integers are variables which are instances (objects) of the
int class.
Note for C/C++/Java/C# Programmers
Note that even integers are treated as objects (of the int class). This is unlike C++ and Java
(before version 1.5) where integers are primitive native types. See help(int) for more details
on the class.
C# and Java 1.5 programmers will be familiar with this concept since it is similar to the boxing
and unboxing concept.
Objects can store data using ordinary variables that belong to the object. Variables that belong to an object
or class are called as fields. Objects can also have functionality by using functions that belong to a
class. Such functions are called methods of the class. This terminology is important because it helps us
to differentiate between functions and variables which are separate by itself and those which belong to a
class or object. Collectively, the fields and methods can be referred to as the attributes of that class.
Fields are of two types - they can belong to each instance/object of the class or they can belong to the
class itself. They are called instance variables and class variables respectively.
A class is created using the class keyword. The fields and methods of the class are listed in an indented
block.
The self
Class methods have only one specific difference from ordinary functions - they must have an extra first
name that has to be added to the beginning of the parameter list, but you do do not give a value for this
parameter when you call the method, Python will provide it. This particular variable refers to the object
itself, and by convention, it is given the name self.
Although, you can give any name for this parameter, it is strongly recommended that you use the name
self - any other name is definitely frowned upon. There are many advantages to using a standard name
- any reader of your program will immediately recognize it and even specialized IDEs (Integrated Development
Environments) can help you if you use self.
Note for C++/Java/C# Programmers
The self in Python is equivalent to the self pointer in C++ and the this reference in Java and C#.
You must be wondering how Python gives the value for self and why you don't need to give a value
for it. An example will make this clear. Say you have a class called MyClass and an instance of this
class called MyObject. When you call a method of this object as MyObject.method(arg1,
arg2), this is automatically converted by Python into MyClass.method(MyObject, arg1,
arg2 - this is what the special self is all about.
This also means that if you have a method which takes no arguments, then you still have to define the
method to have a self argument.