An Introduction to Object-Oriented Programming in Python LG #56

#

#### "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 `self`s 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