4.7 Explicit Initializer Chaining
In many object-oriented languages, the initialization code for class instances (i.e., the class's constructor) will automatically call the initialization code for its superclasses when it begins executing. But there is nothing special about the __init__() method. Python will only call one __init__() method, the first it finds. In Python, you will have to call __init__() methods of superclasses yourself.
How? The problem is, suppose settableCounter had an __init__() method:
def __init__(self,x): ...
that needed to call the __init__() method of its superclass, counter. It couldn't just call
self.__init__ #won't work
That would call settableCounter's __init__() method again, since Python will start searching at the class of object self and stop at the first __init__() method it finds.
Other object-oriented languages have a keyword like super to give a method access to names known in the superclass. Python uses the class name of the superclass. Remember that you can get an unbound method object by writing classname.methodname. You use that to get a method in a superclass whose name is hidden:
counter.__init__(self,x) #would work
Now let's criticize the design of counter and settableCounter. It is part of the design to have an attribute count visible from outside. With the obvious implementation, users are invited to assign values to it, rather than use the set() method. It is considered poor object-oriented design to ever allow the users of a class to assign values to its attributes directly. Instead, they are supposed to call methods to ask the object to do things for them.
Also, settableCounter knows the implementation of counter and assigns a value directly to count in the set() method. This is not as bad as allowing unrelated code to assign to count. Classes generally provide a more lenient interface to their subclasses than to the rest of the world, so it is probably okay for settableCounter to access the count attribute. But this still binds the classes together, so that a change to counter may force a change in settableCounter. It would be better to program defensively and prevent changes in one class from propagating into another.
This discussion becomes more complicated still if we use the special methods __getattr__() and __setattr__() discussed in Chapter 14. They allow what looks like an attribute access to actually call a method. However, we did not use these in counter and settableCounter, and their discussion will have to wait until Chapter 14.