DekGenius.com
[ Team LiB ] Previous Section Next Section

20.1 Classes Generate Multiple Instance Objects

To understand how the multiple objects idea works, you have to first understand that there are two kinds of objects in Python's OOP model—class objects and instance objects. Class objects provide default behavior and serve as factories for instance objects. Instance objects are the real objects your programs process; each is a namespace in its own right, but inherits (i.e., has automatic access to) names in the class it was created from. Class objects come from statements, and instances from calls; each time you call a class, you get a new instance of that class.

This object generation concept is very different from any of the other program constructs we've seen so far in this book. In effect, classes are factories for making many instances. By contrast, there is only one copy of each module imported (in fact, this is one reason that we have to call reload, to update the single module object).

Next, we'll summarize the bare essentials of Python OOP. Classes are in some ways similar to both def and modules, but they may be quite different than what you're used to in other languages.

20.1.1 Class Objects Provide Default Behavior

  • The class statement creates a class object and assigns it a name. Just like the function def statement, the Python class statement is an executable statement. When reached and run, it generates a new class object and assigns it to the name in the class header. Also like def, class statements typically run when the file they are coded in is first imported.

  • Assignments inside class statements make class attributes. Just like module files, assignments within a class statement generate attributes in a class object. After running a class statement, class attributes are accessed by name qualification: object.name.

  • Class attributes provide object state and behavior. Attributes of a class object record state information and behavior, to be shared by all instances created from the class; function def statements nested inside a class generate methods, which process instances.

20.1.2 Instance Objects Are Concrete Items

  • Calling a class object like a function makes a new instance object. Each time a class is called, it creates and returns a new instance object. Instances represent concrete items in your program's domain.

  • Each instance object inherits class attributes and gets its own namespace. Instance objects created from classes are new namespaces; they start out empty, but inherit attributes that live in the class object they were generated from.

  • Assignments to attributes of self in methods make per-instance attributes. Inside class method functions, the first argument (called self by convention) references the instance object being processed; assignments to attributes of self create or change data in the instance, not the class.

20.1.3 A First Example

Let's turn to a real example to show how these ideas work in practice. To begin, let's define a class named FirstClass, by running a Python class statement interactively:

>>> class FirstClass:                # Define a class object.
...     def setdata(self, value):    # Define class methods.
...         self.data = value        # self is the instance.
...     def display(self):
...         print self.data          # self.data: per instance

We're working interactively here, but typically, such a statement would be run when the module file it is coded in is imported. Like functions, your class won't even exist until Python reaches and runs this statement.

Like all compound statements, class starts with a header line that lists the class name, followed by a body of one or more nested and (usually) indented statements. Here, the nested statements are defs; they define functions that implement the behavior the class means to export. As we've learned, def is really an assignment; here, it assigns to the names setdata and display in the class statement's scope, and so generates attributes attached to the class: FirstClass.setdata, and FirstClass.display.

Functions inside a class are usually called methods; they're normal defs, but the first argument automatically receives an implied instance object when called—the subject of a call. We need a couple of instances to see how:

>>> x = FirstClass(  )                 # Make two instances.
>>> y = FirstClass(  )                 # Each is a new namespace.

By calling the class this way (notice the parenthesis), it generates instance objects, which are just namespaces that have access to their class's attributes. Properly speaking, at this point we have three objects—two instances and a class. Really, we have three linked namespaces, as sketched in Figure 20-1. In OOP terms, we say that x "is a" FirstClass, as is y.

Figure 20-1. Classes and instances are linked namespace objects
figs/lpy2_2001.gif

The two instances start empty, but have links back to the class they were generated from. If we qualify an instance with the name of an attribute that lives in the class object, Python fetches the name from the class by inheritance search (unless it also lives in the instance):

>>> x.setdata("King Arthur")     # Call methods: self is x
>>> y.setdata(3.14159)           # Runs: FirstClass.setdata(y, 3.14159)

Neither x nor y has a setdata of its own; instead, Python follows the link from instance to class if an attribute doesn't exist in an instance. And that's about all there is to inheritance in Python: it happens at attribute qualification time, and just involves looking up names in linked objects (e.g., by following the is-a links in Figure 20-1).

In the setdata function inside FirstClass, the value passed in is assigned to self.data. Within a method, self—the name given to the leftmost argument by convention—automatically refers to the instance being processed (x or y), so the assignments store values in the instances' namespaces, not the class (that's how the data names in Figure 20-1 are created).

Since classes generate multiple instances, methods must go through the self argument to get to the instance to be processed. When we call the class's display method to print self.data, we see that it's different in each instance; on the other hand, display is the same in x and y, since it comes (is inherited) from the class:

>>> x.display(  )                      # self.data differs in each.
King Arthur
>>> y.display(  )
3.14159

Notice that we stored different object types in the data member (a string and a floating-point). Like everything else in Python, there are no declarations for instance attributes (sometimes called members); they spring into existence the first time they are assigned a value, just like simple variables. In fact, we can change instance attributes either in the class itself by assigning to self in methods, or outside the class by assigning to an explicit instance object:

>>> x.data = "New value"               # Can get/set attributes 
>>> x.display(  )                      # outside the class too.
New value

Although less common, we could even generate a brand new atribute on the instance, by assigning to its name outside the class's method functions:

>>> x.anothername = "spam"           # Can get/set attributes 

This would attach a new attribute called anothername to the instance object x, which may or may not be used by any of the class's methods. Classes usually create all the instance's attributes by assignment to the self argument, but they don't have to; programs can fetch, change, or create attributes on any object that they have a reference to.

    [ Team LiB ] Previous Section Next Section