A Quick Start Introduction to Python Programming - 4

Sunday, September 14, 2008

In this section, we will explore Object Oriented Programming in Python, we will see the differences between Python class objects and instance objects, public, private methods, inheritance, class variables, instance variables, __init__ functions, etc.

If you want to read this quick start introduction into python programming from the beginning, do visit "A Quickstart Introduction to Python Programming - 1"., I would recommend you to start from that section if you are a newbie as understanding OOPs concepts requires some foundation.

Python's class and object paradigms are little different from that of other high level languages like C++ and Java, if you are a hard core C++ or a java programmer your are bound to some surprises as I mentioned earlier, "Everything in Python is an Object" and this includes python classes too which in turn is a python object. Confused! So was I when I learnt this first, but its rather very simple to understand as we will see below.

Listing 8: oops.py


#
# OOPS concepts in python
# oops.py
# Author: S.Prasanna
#

import traceback

class Base:
def __init__ (self):
print "I am the base class's init"

def basemethod (self):
print "I am a base class method"

class Derived(Base):
# This is a class variable
classvar = 10

def __privatemethod (self):
""" This is a private method """
print "I am a private method, but I can still be accessed from outside"

def __init__ (self):
self.instancevar = 20
print "I am the super class's init"
Base.__init__(self)

def callbasemethod(self):
self.basemethod()

if __name__ == "__main__":

print "Derived class's class object:", Derived
print "Type of Derived's class object:", type(Derived)
print "Creating Instance od Derived class...."
derivedinstance = Derived()
print "Type of Derived's instance object =", type(derivedinstance)
print "Derived instance's class object =", derivedinstance.__class__

print "\nDerived class's classvar =", Derived.classvar
print "Derived instance's classvar =", derivedinstance.classvar # Same as Derived.classvar
print "Derived instance's instancevar =", derivedinstance.instancevar
print "Changing Derived's class variable classvar...."
Derived.classvar = 40 #Change Derived's class variable
derivedinstance.classvar = 50 #This becomes a new instance variable, won't change the class variable
print "Derived class's classvar =", Derived.classvar
print "Derived instance's classvar =", derivedinstance.classvar

try:
print "Trying to call a private method:"
derivedinstance.__privatemethod()
except:
traceback.print_exc()

print "Calling a private method using shortcut:"
derivedinstance._Derived__privatemethod()

print "Calling Derived's superclass method"
derivedinstance.callbasemethod()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

Output:

IDLE 1.2.2 ==== No Subprocess ====
>>>
Derived class's class object: __main__.Derived
Type of Derived's class object:
Creating Instance od Derived class....
I am the super class's init
I am the base class's init
Type of Derived's instance object =
Derived instance's class object = __main__.Derived

Derived class's classvar = 10
Derived instance's classvar = 10
Derived instance's instancevar = 20
Changing Derived's class variable classvar....
Derived class's classvar = 40
Derived instance's classvar = 50
Trying to call a private method:
Traceback (most recent call last):
File "C:\Prasanna\myblogs\prasannatech.net\entries\python_TOI\oops.py", line 52, in
derivedinstance.__privatemethod()
AttributeError: Derived instance has no attribute '__privatemethod'
Calling a private method using shortcut:
I am a private method, but I can still be accessed from outside
Calling Derived's superclass method
I am a base class method
>>>

Explanation:

Lines 8 - 14
class Base:
def __init__ (self):
print "I am the base class's init"

def basemethod (self):
print "I am a base class method"
Here we declared a Base class which has two functions namely __init__ and basemethod. The syntax for declaring a class is similar to that of declaring any other functions in python, except that we use a class keyword to declare a class.

The __init__ function is similar to a constructor (although its not) which will initialize any class/instance variables or other attributes of a class, the Base class declares another method which just prints a line.

Lines 15 - 30
class Derived (Base):
# This is a class variable
classvar = 10

def __privatemethod (self):
""" This is a private method """
print "I am a private method, but I can still be accessed from outside"

def __init__ (self):
self.instancevar = 20
print "I am the super class's init"
Base.__init__(self)

def callbasemethod(self):
self.basemethod()
Here we declare a Derived class which inherits the Base class. The syntax for extending a class is very simple as all we need to do is to mention the class to be extended inside the class declaration (inside the parenthesis).

We then declare a class level variable classvar = 10. Note that there are some differences between declaring a variable inside the __init__ function or any other methods inside the class and declaring above these methods at the class level. Now this variable is similar to a static variable in other languages like java with only one copy per class as we will see below. The __init__ function is used to initialize the class attributes, athough its similar to a constructor as in other languages like Java, C++, its actually not as the class object already exists before calling the __init__ method, but this method executes everytime one creates an instance of this type.

Then we define a private method __privatemethod, the syntax for declaring a private method is little different here, if we declare a method with __ before the method name, it will be interpreted as a private method. By default a private function cannot be accessed outside the class, but in python we can actually access this method as shown below (Python follows the philosophy Bad habits of OOPs ahould be avoided if not prohibited). The __init__ also defines an instance variable specific to the instance and initializes it.

We also declare a callbasemethod which will call the superclass's basemethod, also note that whenever we define __init__ method, we have to explicitly call the superclass's init method (Base.__init__ method).

Another thing of importance here is the self keyword which is a pointer (in abstract terms) to that specific instance of the class. The self parameter is used to specify that a method belongs to that instance of a class or in other words we should use self as the first parameter to all class functions, __init__ method and other variable assignments which belongs to that specific class instance.

Lines 31 - 60
if __name__ == "__main__":

print "Derived class's class object:", Derived
print "Type of Derived's class object:", type(Derived)
print "Creating Instance od Derived class...."
derivedinstance = Derived()
print "Type of Derived's instance object =", type(derivedinstance)
print "Derived instance's class object =", derivedinstance.__class__

print "\nDerived class's classvar =", Derived.classvar
print "Derived instance's classvar =", derivedinstance.classvar # Same as Derived.classvar
print "Derived instance's instancevar =", derivedinstance.instancevar
print "Changing Derived's class variable classvar...."
Derived.classvar = 40 #Change Derived's class variable
derivedinstance.classvar = 50 #This becomes a new instance variable, won't change the class variable
print "Derived class's classvar =", Derived.classvar
print "Derived instance's classvar =", derivedinstance.classvar

try:
print "Trying to call a private method:"
derivedinstance.__privatemethod()
except:
traceback.print_exc()

print "Calling a private method using shortcut:"
derivedinstance._Derived__privatemethod()

print "Calling Derived's superclass method"
derivedinstance.callbasemethod()
Here we print the derived class's object type and the derived instance's object type. Note that a class in itself is a python object of type "class" and an instance is another object of type "instance". Therefore the type of Derived would return (line 34) and type of the instance derivedinstance would return (line 37).

The statement derivedinstance = Derived() creates an instance of Derived and the instance's type would return , if we want to find the class associated with this instance, we use the __class__ attribute of derivedinstance which would print that instance's class object (line 39).

Now comes the interesting part, the Dervied class has a class level attribute classvar and we have an instance class of derived derivedinstance. Now if we want to print the class variable classvar, the below statements would print the same or in other words,

Derived.classvar = derivedinstance.classvar (both would print 10), this is also similar to other languages like java where a static variable can be accessed using the class name or the instance name qualifier. Now an interesting case comes when we try to change the class level variable in lines 45 and 46 using

Derived.classvar = 40
derivedinstance.classvar = 50

After the change Derived.classvar would print 40 and derivedinstance.classvar would print 50, how? This is because the statement

derivedinstance.classvar = 50 actually creates a new instance variable classvar and assigns it to 50 or put it in other way this is similar to creating a new instance variable in a method or in an __init__ statement of a class.

The statement derivedinstance.classvar = 50 is similar to self.classvar = 50 (self corresponds to that specific instance of Derived). This understanding is important when it comes to Object oriented programming in python.

Line 45 prints the instance variable instancevar of the class which is straightforward.

Lines 49 - 54 Here we try to access a private method of a class, which results in an exception (AttributeError).

Then we use the syntax
derivedinstance._Derived__privatemethod()
to access the private method, though its a bad practice its possible to do it in python.

In Line 60, we then access the superclass's method from the subclass.

To put in a nutshell....

1. A class in python is a python object of type class and an instance of a class is an object of type instance.
2. The __class__ attribute of an instance can be used to access the class corresponding to that instance.
3. The __init__ method of a class executes everytime an instance is created.
4. Python has private member functions, but they can still be accessed from outside or in other words, in sync with the philosophy "Bad OOP practices should be avoided, but not prohibited".
5. Class variables are declared above the methods and __init__ functions and instance variables are declared within class methods and start sith the self identifier.

In the next (concluding section) we will see more object concepts in python, some introduction to threads and other useful python references.

Continued here. A Quick Start to Introduction to Python Programming - 5.


No comments:


Copyright © 2016 Prasanna Seshadri, www.prasannatech.net, All Rights Reserved.
No part of the content or this site may be reproduced without prior written permission of the author.