Learning Python - Mark Lutz [439]
Class Decorators and Metaclasses
Function decorators turned out to be so useful that Python 2.6 and 3.0 expanded the model, allowing decorators to be applied to classes as well as functions. In short, class decorators are similar to function decorators, but they are run at the end of a class statement to rebind a class name to a callable. As such, they can be used to either manage classes just after they are created, or insert a layer of wrapper logic to manage instances when they are later created. Symbolically, the code structure:
def decorator(aClass): ...
@decorator
class C: ...
is mapped to the following equivalent:
def decorator(aClass): ...
class C: ...
C = decorator(C)
The class decorator is free to augment the class itself, or return an object that intercepts later instance construction calls. For instance, in the example in the section Counting instances per class with class methods, we could use this hook to automatically augment the classes with instance counters and any other data required:
def count(aClass):
aClass.numInstances = 0
return aClass # Return class itself, instead of a wrapper
@count
class Spam: ... # Same as Spam = count(Spam)
@count
class Sub(Spam): ... # numInstances = 0 not needed here
@count
class Other(Spam): ...
Metaclasses are a similarly advanced class-based tool whose roles often intersect with those of class decorators. They provide an alternate model, which routes the creation of a class object to a subclass of the top-level type class, at the conclusion of a class statement:
class Meta(type):
def __new__(meta, classname, supers, classdict): ...
class C(metaclass=Meta): ...
In Python 2.6, the effect is the same, but the coding differs—use a class attribute instead of a keyword argument in the class header:
class C:
__metaclass__ = Meta
...
The metaclass generally redefines the __new__ or __init__ method of the type class, in order to assume control of the creation or initialization of a new class object. The net effect, as with class decorators, is to define code to be run automatically at class creation time. Both schemes are free to augment a class or return an arbitrary object to replace it—a protocol with almost limitless class-based possibilities.
For More Details
Naturally, there’s much more to the decorator and metaclass stories than I’ve shown here. Although they are a general mechanism, decorators and metaclasses are advanced features of interest primarily to tool writers, not application programmers, so we’ll defer additional coverage until the final part of this book:
Chapter 37 shows how to code properties using function decorator syntax.
Chapter 38 has much more on decorators, including more comprehensive examples.
Chapter 39 covers metaclasses, and more on the class and instance management story.
Although these chapters cover advanced topics, they’ll also provide us with a chance to see Python at work in more substantial examples than much of the rest of the book was able to provide.
Class Gotchas
Most class issues can be boiled down to namespace issues (which makes sense, given that classes are just namespaces with a few extra tricks). Some of the topics we’ll cover in this section are more like case studies of advanced class usage than real problems, and one or two of these gotchas have been eased by recent Python releases.
Changing Class Attributes Can Have Side Effects
Theoretically speaking, classes (and class instances) are mutable objects. Like built-in lists and dictionaries, they can be changed in-place by assigning to their attributes—and as with lists and dictionaries, this means that changing a class or instance object may impact multiple references to it.
That’s usually what we want (and is how objects change their state in general), but awareness of this issue becomes especially critical when changing class attributes. Because all instances generated