type
To understand metaclasses we need to understand Python’s type
function. type
has two function signatures.
-
With one argument passed,
type
returns the type (class) of the object passed. Keep in mind that classes in Python are objects. -
With three arguments passed,
type
returns a class. This is the one we will be talking about.
As the documentation states:
With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the name attribute; the bases tuple itemizes the base classes and becomes the bases attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the dict attribute. For example, the following two statements create identical type objects:
hooks
Metaclasses are subclasses of type
. Just as you can subclass another class, you can also subclass type
. Overriding hooks in this subclass will allow you to dynamically change class creation.
-
__prepare__
is used to initialize the class’s namespace. It should return a dictionary-like object (one supporting the__getitem__
and__setitem__
methods) that will hold the class’s namespace. This hook only exists in Python3. -
__new__
is used to create the new metaclass. It is passed the populated namespace. -
__init__
is used to initialize attributes of the class.
example
Here is an example of a metaclass.
The __prepare__
hook is returning an ordered dictionary. This means that the order in which the classes attributes are defined matters.
The __new__
hook is changing all non “magic” attributes to be uppercased and storing the original namespace as a lower cased attribute.
The __init__
hook does what you would guess it does but for one small thing. The namespace that it is passed is the one returned from __prepare__
not the one created in __new__
(i.e. the one the class will have).
Now we can use this metaclass to dynamically change how our classes are defined.
By passing the metaclass
keyword argument to the class, we change the class’s creation mechanism from type
to MyMetaClass
. Note: metaclass’s are specified as a keyword argument in Python3 and using the __metaclass__
class attribute in Python2.
At the end of our module…
The resulting output is
On class definition, the metaclass’s three hook methods are called in the correct order. I passed the keyword argument for funsies to show how it works and propagates through the calls to the hook methods.
Then when the Foo
class is instantiated, the __call__
hook of the metaclass fires before the class’s __new__
and __init__
class hooks do. Remember though, if you do override a metaclass’s __call__
hook, the class’s __new__
hook will not be called unless you do it.
uses
Usually none. Metaclasses are fun to play around with, but unless you are doing something really fancy, you probably won’t need them. If you think you do, think again for a bit. How could use superclasses, class attributes, or properties to solve the problem?
Their canonical use case is developing an ORM where you want class creation to trigger table creation in a database. SQLAlchemy is an example of a Python ORM that uses metaclasses.