Online Book Reader

Home Category

Learning Python - Mark Lutz [571]

By Root 1586 0
However, we’ll see later that a simple function-based metaclass can often work much like a class decorator, which allows the metaclasses to manage instances as well as classes.

Instances Versus Inheritance

Because metaclasses are specified in similar ways to inheritance superclasses, they can be a bit confusing at first glance. A few key points should help summarize and clarify the model:

Metaclasses inherit from the type class. Although they have a special role, metaclasses are coded with class statements and follow the usual OOP model in Python. For example, as subclasses of type, they can redefine the type object’s methods, overriding and customizing them as needed. Metaclasses typically redefine the type class’s __new__ and __init__ to customize class creation and initialization, but they can also redefine __call__ if they wish to catch the end-of-class creation call directly. Although it’s unusual, they can even be simple functions that return arbitrary objects, instead of type subclasses.

Metaclass declarations are inherited by subclasses. The metaclass=M declaration in a user-defined class is inherited by the class’s subclasses, too, so the metaclass will run for the construction of each class that inherits this specification in a superclass chain.

Metaclass attributes are not inherited by class instances. Metaclass declarations specify an instance relationship, which is not the same as inheritance. Because classes are instances of metaclasses, the behavior defined in a metaclass applies to the class, but not the class’s later instances. Instances obtain behavior from their classes and superclasses, but not from any metaclasses. Technically, instance attribute lookups usually search only the __dict__ dictionaries of the instance and all its classes; the metaclass is not included in inheritance lookup.

To illustrate the last two points, consider the following example:

class MetaOne(type):

def __new__(meta, classname, supers, classdict): # Redefine type method

print('In MetaOne.new:', classname)

return type.__new__(meta, classname, supers, classdict)

def toast(self):

print('toast')

class Super(metaclass=MetaOne): # Metaclass inherited by subs too

def spam(self): # MetaOne run twice for two classes

print('spam')

class C(Super): # Superclass: inheritance versus instance

def eggs(self): # Classes inherit from superclasses

print('eggs') # But not from metclasses

X = C()

X.eggs() # Inherited from C

X.spam() # Inherited from Super

X.toast() # Not inherited from metaclass

When this code is run, the metaclass handles construction of both client classes, and instances inherit class attributes but not metaclass attributes:

In MetaOne.new: Super

In MetaOne.new: C

eggs

spam

AttributeError: 'C' object has no attribute 'toast'

Although detail matters, it’s important to keep the big picture in mind when dealing with metaclasses. Metaclasses like those we’ve seen here will be run automatically for every class that declares them. Unlike the helper function approaches we saw earlier, such classes will automatically acquire whatever augmentation the metaclass provides. Moreover, changes in such augmentation only need to be coded in one place—the metaclass—which simplifies making modifications as our needs evolve. Like so many tools in Python, metaclasses ease maintenance work by eliminating redundancy. To fully sample their power, though, we need to move on to some larger use-case examples.

Example: Adding Methods to Classes

In this and the following section, we’re going to study examples of two common use cases for metaclasses: adding methods to a class, and decorating all methods automatically. These are just two of the many metaclass roles, which unfortunately consume the space we have left for this chapter; again, you should consult the Web for more advanced applications. These examples are representative of metaclasses in action, though, and they suffice to illustrate the basics.

Moreover, both give us an opportunity to contrast class decorators and metaclasses—our first

Return Main Page Previous Page Next Page

®Online Book Reader