Online Book Reader

Home Category

Learning Python - Mark Lutz [436]

By Root 1716 0
function name in the class scope (so it won’t clash with other names in the module), moves the function code closer to where it is used (inside the class statement), and allows subclasses to customize the static method with inheritance—a more convenient approach than importing functions from the files in which superclasses are coded. The following subclass and new testing session illustrate:

class Sub(Spam):

def printNumInstances(): # Override a static method

print("Extra stuff...") # But call back to original

Spam.printNumInstances()

printNumInstances = staticmethod(printNumInstances)

>>> a = Sub()

>>> b = Sub()

>>> a.printNumInstances() # Call from subclass instance

Extra stuff...

Number of instances: 2

>>> Sub.printNumInstances() # Call from subclass itself

Extra stuff...

Number of instances: 2

>>> Spam.printNumInstances()

Number of instances: 2

Moreover, classes can inherit the static method without redefining it—it is run without an instance, regardless of where it is defined in a class tree:

>>> class Other(Spam): pass # Inherit static method verbatim

>>> c = Other()

>>> c.printNumInstances()

Number of instances: 3

Counting Instances with Class Methods

Interestingly, a class method can do similar work here—the following has the same behavior as the static method version listed earlier, but it uses a class method that receives the instance’s class in its first argument. Rather than hardcoding the class name, the class method uses the automatically passed class object generically:

class Spam:

numInstances = 0 # Use class method instead of static

def __init__(self):

Spam.numInstances += 1

def printNumInstances(cls):

print("Number of instances:", cls.numInstances)

printNumInstances = classmethod(printNumInstances)

This class is used in the same way as the prior versions, but its printNumInstances method receives the class, not the instance, when called from both the class and an instance:

>>> a, b = Spam(), Spam()

>>> a.printNumInstances() # Passes class to first argument

Number of instances: 2

>>> Spam.printNumInstances() # Also passes class to first argument

Number of instances: 2

When using class methods, though, keep in mind that they receive the most specific (i.e., lowest) class of the call’s subject. This has some subtle implications when trying to update class data through the passed-in class. For example, if in module test.py we subclass to customize as before, augment Spam.printNumInstances to also display its cls argument, and start a new testing session:

class Spam:

numInstances = 0 # Trace class passed in

def __init__(self):

Spam.numInstances += 1

def printNumInstances(cls):

print("Number of instances:", cls.numInstances, cls)

printNumInstances = classmethod(printNumInstances)

class Sub(Spam):

def printNumInstances(cls): # Override a class method

print("Extra stuff...", cls) # But call back to original

Spam.printNumInstances()

printNumInstances = classmethod(printNumInstances)

class Other(Spam): pass # Inherit class method verbatim

the lowest class is passed in whenever a class method is run, even for subclasses that have no class methods of their own:

>>> x, y = Sub(), Spam()

>>> x.printNumInstances() # Call from subclass instance

Extra stuff...

Number of instances: 2

>>> Sub.printNumInstances() # Call from subclass itself

Extra stuff...

Number of instances: 2

>>> y.printNumInstances()

Number of instances: 2

In the first call here, a class method call is made through an instance of the Sub subclass, and Python passes the lowest class, Sub, to the class method. All is well in this case—since Sub’s redefinition of the method calls the Spam superclass’s version explicitly, the superclass method in Spam receives itself in its first argument. But watch what happens for an object that simply inherits the class method:

>>> z = Other()

>>> z.printNumInstances()

Number of instances: 3

This last call here passes

Return Main Page Previous Page Next Page

®Online Book Reader