Declaring Metaclasses

As we’ve just seen, classes are created by the type class by default. To tell Python to create a class with a custom metaclass instead, you simply need to declare a metaclass to intercept the normal class creation call. How you do so depends on which Python version you are using. In Python 3.0, list the desired metaclass as a keyword argument in the class header:

class Spam(metaclass=Meta):                   # 3.0 and later

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

Inheritance superclasses can be listed in the header as well, before the metaclass. In the following, for example, the new class Spam inherits from Eggs but is also an instance of and is created by Meta:

class Spam(Eggs, metaclass=Meta):             # Other supers okay

We can get the same effect in Python 2.6, but we must specify the metaclass differently—using a class attribute instead of a keyword argument. The object derivation is required to make this a new-style class, and this form no longer works in 3.0 as the attribute is simply ignored:

class spam(object):                           # 2.6 version (only)
    __metaclass__ = Meta

In 2.6, a module-global __metaclass__ variable is also available to link all classes in the module to a metaclass. This is no longer supported in 3.0, as it was intended as a temporary measure to make it easier to default to new-style classes without deriving every class from object.

When declared in these ways, the call to create the class object run at the end of the class statement is modified to invoke the metaclass instead of the type default:

class = Meta(classname, superclasses, attributedict)

And because the metaclass is a subclass of type, the type class’s __call__ delegates the calls to create and initialize the new class object to the metaclass, if it defines custom versions of these methods:

Meta.__new__(Meta, classname, superclasses, attributedict)
Meta.__init__(class, classname, superclasses, attributedict)

To demonstrate, here’s the prior section’s example again, augmented with a 3.0 metaclass specification:

class Spam(Eggs, metaclass=Meta):      # Inherits from Eggs, instance of Meta
    data = 1                           # Class data attribute
    def meth(self, arg):               # Class method attribute
        pass

At the end of this class statement, Python internally runs the following to create the class object:

Spam = Meta('Spam', (Eggs,), {'data': 1, 'meth': meth, '__module__': '__main__'})

If the metaclass defines its own versions of __new__ or __init__, they will be invoked in turn during this call by the inherited type class’s __call__ method, to create and initialize the new class. The next section shows how we might go about coding this final piece of the metaclass puzzle.