Next / Previous / Contents / TCC Help System / NM Tech homepage

26. Classes: Defining your own types

This section assumes you already understand the basics of object-oriented programming in Python, and that you know the meaning of concepts such as class, instance, method, and attribute. For a general tutorial on these concepts, see the introduction to object-oriented Python programming in the Tech Computer Center's Python tutorial.

Here is the general form of the class declaration for some class C with one or more parent classes P1, P2, …:

class C(P1, P2, ...):
    attribute definitions
    ...

To declare a class that does not inherit from any parent classes:

class C:
    attribute definitions
    ...

The attribute definitions may include any number of def blocks that declare methods of the class, and any number of class variable declarations.

Functionally, a class is really just a namespace. This namespace is just a place to store the pieces of the class mechanisms: its methods and class variables.

A brief conversational session may serve to illustrate these concepts. We'll make use of the built-in function dir() to show the contents of the class's namespace; see Section 21.5, “dir(): Display a namespace's names”.

>>> class Taunter:          1
...     tauntCount  =  0    2
...     def taunt(self):    3
...         print "Go away, or I shall taunt you a second time!"
... 
>>> dir(Taunter)            4
['__doc__', '__module__', 'taunt', 'tauntCount']
>>> type(Taunter.__doc__)
<type 'NoneType'>
>>> Taunter.__module__
'__main__'
>>> Taunter.tauntCount      5
0
>>> Taunter.taunt           6
<unbound method Taunter.taunt>
1

When Python reads this line, it adds the name Taunter to the current local namespace, bound to a new, empty namespace of type class.

2

Because this assignment takes place inside class Taunter but not inside a def, name tauntCount becomes a class variable, bound to an int value of zero.

3

The next two lines define a method named taunt() within the class.

4

After we've finished entering the class definition, we use dir(Taunter) to see what names are in the class's namespace. Variables __doc__ and __module__ are added automatically. Because there was no documentation string in the class, __doc__ is bound to None. The __module__ variable has the value '__main__' because the class was entered in conversational mode.

5

To retrieve the value of a class variable V in class C, use the syntax “C.V”.

6

Name taunt in the class namespace is bound to an object of type “unbound method.” An unbound method is a method (function) that is inside a class, but it is not associated with an instance of the class.

An instance of a class is also a namespace. When the instance is created, all the names from the class's namespace are copied into the instance namespace. From that point on, any changes made to the instance's namespace do not affect the class namespace:

>>> frenchy = Taunter()             1
>>> dir(frenchy)
['__doc__', '__module__', 'taunt', 'tauntCount']
>>> frenchy.where = 'crenelations'  2
>>> dir(frenchy)                    3
['__doc__', '__module__', 'where', 'taunt', 'tauntCount']
>>> frenchy.where
'crenelations'
>>> dir(Taunter)
['__doc__', '__module__', 'taunt', 'tauntCount']
>>> frenchy.tauntCount              4
0
>>> frenchy.tauntCount += 1         5
>>> frenchy.tauntCount
1
>>> Taunter.tauntCount
0
>>> type(frenchy.taunt)             6
<type 'instancemethod'>
>>> frenchy.taunt()                 7
Go away, or I shall taunt you a second time!
>>> Taunter.taunt(frenchy)          8
Go away, or I shall taunt you a second time!
1

This class does not have a constructor (__init__) method, so when an instance is created, the instance is a namespace with the same names as the class, and the same values.

2

This line adds a new name where to the instance's namespace. It is bound to the string value 'crenelations'.

3

Note that the instance namespace now contains the name where, but the class's namespace is unchanged.

4

To retrieve an attribute A of an instance I, use the syntax “I.A”. Initially, the instance variable has the same value as the class variable of the same name.

5

Here, we add one to the instance variable tauntCount. The instance variable has the new value, but the class variable tauntCount is unchanged.

6

Within the instance namespace, name taunt is now a bound method: it is associated with the instance frenchy.

The next two lines show two equivalent methods of calling the taunt method.

7

Most method calls are bound method calls. To call a bound method B of an instance I, use the syntax “I.B(...)”.

When a method B is bound to an instance I, the instance namespace I becomes the “self” argument passed in to the method.

8

This line has the same effect as the previous line, but it is an unbound method call.

The expression “Taunter.taunt” retrieves the unbound method from the class definition. When you call an unbound method, you must supply the “self” argument explicitly as the first argument.

Unbound method calls are not terribly common, but you will need to know about them when you write the constructor for a derived class: you must call the parent class constructor as an unbound call. Generally, if class D has parent class C, the derived class might look something like this:

class D(C):
    def __init__(self, ...):
        C.__init__(self, ...)
        ...

Namespaces are very much like dictionaries. Where a dictionary has unique keys, a namespace has unique names. As a matter of fact, classes and instances have a special built-in attribute called “__dict__” which, for most purposes, is the namespace as a dictionary. Continuing the examples above:

>>> Taunter.__dict__
{'taunt': <function taunt at 0xb7ed002c>, '__module__': '__main__', 'tau
ntCount': 0, '__doc__': None}
>>> newFrenchy=Taunter()
>>> newFrenchy.__dict__
{}
>>> frenchy.__dict__
{'tauntCount': 1, 'where': 'crenelations'}

The class's dictionary has the four names we expect: the built-ins __module__ and __doc__, the class variable tauntCount, and the method taunt.

But notice that the __dict__ attribute of the newly created instance newFrenchy does not have the four names copied from the class. In fact, it is empty. And the __dict__ of instance frenchy contains only the names that have changed since its instantation.

What actually happens when you refer to an attribute is that Python looks first in the instance's __dict__; if the name is not found there, it looks in the __dict__ of the class. For derived classes, Python will also search the __dict__ attributes of all the ancestor classes.

So, in our example, a reference to frenchy.tauntCount would find the value of 1 in the instance. A reference to newFrenchy.tauntCount would fail to find that name in newFrench.__dict__, but would succeed in finding the class variable value 0 in Taunter.__dict__['tauntCount'].

Let's now look at the life cycles of classes in more detail. Due to improvements made in the language since it was first introduced, Python has two kinds of classes, old-style and new-style. We encourage you to use new-style classes; old-style classes will no longer be supported in the next major release, Python 3000.

In most respects, the two classes perform identically.