Learning Python - Mark Lutz [338]
As we’ll see later, Python passes in the implied instance to a special first argument in the method, called self by convention. As we’ll also learn, methods can be called through either an instance (e.g., bob.giveRaise()) or a class (e.g., Employee.giveRaise(bob)), and both forms serve purposes in our scripts. To see how methods receive their subjects, though, we need to move on to some code.
Coding Class Trees
Although we are speaking in the abstract here, there is tangible code behind all these ideas. We construct trees, and their objects with class statements and class calls, which we’ll meet in more detail later. In short:
Each class statement generates a new class object.
Each time a class is called, it generates a new instance object.
Instances are automatically linked to the classes from which they are created.
Classes are linked to their superclasses by listing them in parentheses in a class header line; the left-to-right order there gives the order in the tree.
To build the tree in Figure 25-1, for example, we would run Python code of this form (I’ve omitted the guts of the class statements here):
class C2: ... # Make class objects (ovals)
class C3: ...
class C1(C2, C3): ... # Linked to superclasses
I1 = C1() # Make instance objects (rectangles)
I2 = C1() # Linked to their classes
Here, we build the three class objects by running three class statements, and make the two instance objects by calling the class C1 twice, as though it were a function. The instances remember the class they were made from, and the class C1 remembers its listed superclasses.
Technically, this example is using something called multiple inheritance, which simply means that a class has more than one superclass above it in the class tree. In Python, if there is more than one superclass listed in parentheses in a class statement (like C1’s here), their left-to-right order gives the order in which those superclasses will be searched for attributes.
Because of the way inheritance searches proceed, the object to which you attach an attribute turns out to be crucial—it determines the name’s scope. Attributes attached to instances pertain only to those single instances, but attributes attached to classes are shared by all their subclasses and instances. Later, we’ll study the code that hangs attributes on these objects in depth. As we’ll find:
Attributes are usually attached to classes by assignments made within class statements, and not nested inside function def statements.
Attributes are usually attached to instances by assignments to a special argument passed to functions inside classes, called self.
For example, classes provide behavior for their instances with functions created by coding def statements inside class statements. Because such nested defs assign names within the class, they wind up attaching attributes to the class object that will be inherited by all instances and subclasses:
class C1(C2, C3): # Make and link class C1
def setname(self, who): # Assign name: C1.setname
self.name = who # Self is either I1 or I2
I1 = C1() # Make two instances
I2 = C1()
I1.setname('bob') # Sets I1.name to 'bob'
I2.setname('mel') # Sets I2.name to 'mel'
print(I1.name) # Prints 'bob'
There’s nothing syntactically unique about def in this context. Operationally, when a def appears inside a class like this, it is usually known as a method, and it automatically receives a special first argument—called self by convention—that provides a handle back to the instance to be processed.[58]
Because classes are factories for multiple instances, their methods usually go through this automatically passed-in self argument whenever they need to fetch or set attributes of the particular instance being processed by a method call. In the preceding code, self is used to store a name in