ALINK="#FF0000">

LINUX GAZETTE

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]

"Linux Gazette...making Linux just a little more fun!"


An Introduction to Object-Oriented Programming in Python

By Michael Orr


Somebody asked Michael Williams if he could do Python and Java versions of his article An Introduction to Object-Oriented Programming in C++. Here's a Python version of the code. I'll comment on the differences between C++ and Python. Perhaps somebody else can write a Java version?

I am assuming you know the basics of Python. If not, see the excellent Tutorial and the other documentation at http://www.python.org/doc/.

Houses and more houses

To represent Michael's house (in section Classy! in the C++ article), we can use the following code: (text version)

#! /usr/bin/python
"""house.py -- A house program.
This is a documentation string surrounded by triple quotes.
"""

class House:
	pass

my_house = House()
my_house.number = 40
my_house.rooms = 8
my_house.garden = 1

print "My house is number", my_house.number
print "It has", my_house.rooms, "rooms"
if my_house.garden:
	garden_text = "has"
else:
	garden_text = "does not have"
print "It", garden_text, "a garden"
If we run it, it prints:
My house is number 40
It has 8 rooms
It has a garden

What does this program do? First, we define what a generic house is in the class block. pass means "do nothing" and is required if the block would otherwise be empty. Then we create an instance (that is, a particular house) by calling the class name as if it were a function. The house is then stored in the variable my_house.

This house initially has no attributes--if we were to query my_house.number before setting it, we'd get an AttributeError. The next three lines set and create the attributes. This is a difference between the languages: Java instances start out with certain attributes which can never change (although their values can change), but Python instances start out with no attributes, and you can add or delete attributes (or change their type) later. This allows Python to be more flexible in certain dynamic situations.

We can initialize the instance at creation time by including a special __init__ method. (A method is a function which "belongs" to a class.) This program: (text version)

#! /usr/bin/python
"""house2.py -- Another house.
"""

class House:
	def __init__(self, number, rooms, garden):
		self.number = number
		self.rooms = rooms
		self.garden = garden

my_house = House(20, 1, 0)

print "My house is number", my_house.number
print "It has", my_house.rooms, "rooms"
if my_house.garden:
	garden_text = "has"
else:
	garden_text = "does not have"
print "It", garden_text, "a garden"
prints:
My house is number 20
It has 1 rooms
It does not have a garden
Because the class has an __init__ method, it's automatically called when an instance is created. The arguments to House are really the arguments to __init__. Although most programs don't, you can also call __init__ yourself as many times as you want: my_house.__init__(55, 14, 1). This tells the object to "reinitialize itself".

Note that __init__ is defined with an extra first argument, self. But we don't specify self when we call the method. All Python methods work like this. self is in fact the instance itself, and Python supplies it behind the scenes. You need self because it's the only way the method can access the instance's attributes and other methods. Inside the method, self.rooms means the instance's attribute rooms, but rooms means the local variable rooms. Local variables, of course, vanish when the method ends. Python's use of self is parallelled in Perl and other OO languages as well.

Michael didn't tell you, but C++ has a this pointer which works like Python's self. However, in C++ you don't have to type this->house if there is no local variable house, and you never type this on a method definition line. In other words, C++ (and Java) do the same thing as Python and Perl; they just hide it from the programmer.

In fact, self in Python is just a conventional name. You can call it this or me instead if you like. I actually like me better. However, I stick with self so that if somebody else has to maintain my work later, it will be easier for them to read. In contrast, C++'s variable this is magic and cannot be renamed.

In the C++ program, garden is a boolean attribute. Python doesn't have boolean attributes, so we use an integer instead. The expression my_house.garden is true if the attribute is 1 (or any non-zero, non-empty value).

Don't be square

This section corresponds to the "Member Functions" section in Williams' article. I prefer the term "method" over "member function", as Pythoneers usually do. Michael's square.c program would look like this: (text version)

#! /usr/bin/python
"""square.py -- Make some noise about a square.
"""

class Square:
	def __init__(self, length, width):
		self.length = length
		self.width = width

	def area(self):
		return self.length * self.width

my_square = Square(5, 2)
print my_square.area()
prints
10

area should be self explanatory because it works exactly like __init__ above. To reiterate, all the selfs in square.py are required. I have chosen to give Square an __init__ method rather than setting the attributes later, because that's what most Python programmers would do.

Function definitions outside the class definition

Nothing to say here. Python does not allow methods to be defined outside the class. Of course, this doesn't apply to ordinary (non-class) functions.

Public or private?

Not much to say here either. All Python attributes and methods are public. You can emulate private attributes and methods via the double-underscore hack, but most Python programmers don't. Instead, they count on the programmer not to abuse the class's API.

Class constructors

The __init__ method is the constructor.

Arrays and classes

Williams' array example can't be coded literally because of differences between the languages, but one equivalent is: (text version)
#! /usr/bin/python
"""person.py -- A person example.
"""
class Person:
	def __init__(self, age, house_number):
		self.age = age
		self.house_number = house_number

alex = []
for i in range(5):
	obj = Person(i, i)
	alex.append(obj)

print "Alex[3] age is", alex[3].age
print

for alexsub in alex:
	print "Age is", alexsub.age
	print "House number is", alexsub.house_number
This prints:
Alex[3] age is 3

Age is 0
House number is 0
Age is 1
House number is 1
Age is 2
House number is 2
Age is 3
House number is 3
Age is 4
House number is 4                                                          

Python has no equivalent to person alex[5] in the C++ program, which creates an array of five empty instances all at once. Instead, we create an empty list and then use a for loop (which sets i to 0, 1, 2, 3 and 4 respectively) to populate it. The example shows a loop subscripting a list by index number, another loop which gets each element in the list directly, and a print statement which access an element by index number.


Copyright © 2000, Michael Orr
Published in Issue 56 of Linux Gazette, August 2000

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]