Open main menu

Wikibooks β

Python Programming/Metaclasses

< Python Programming

In Python, classes are themselves objects. Just as other objects are instances of a particular class, classes themselves are instances of a metaclass.



The Pep 3115 defines the changes to python 3 metaclasses. In python3 you have a method __prepare__ that is called in the metaclass to create a dictionary or other class to store the class members.[1] Then there is the __new__ method that is called to create new instances of that class. [2]

Class FactoriesEdit

The simplest use of Python metaclasses is a class factory. This concept makes use of the fact that class definitions in Python are first-class objects. Such a function can create or modify a class definition, using the same syntax one would normally use in declaring a class definition. Once again, it is useful to use the model of classes as dictionaries. First, let's look at a basic class factory:

>>> def StringContainer():
...     # define a class
...     class String:
...         def __init__(self):
...             self.content_string = ""
...         def len(self):
...             return len(self.content_string)
...     # return the class definition
...     return String
>>> # create the class definition
... container_class = StringContainer()
>>> # create an instance of the class
... wrapped_string = container_class()
>>> # take it for a test drive
... wrapped_string.content_string = 'emu emissary'
>>> wrapped_string.len()

Of course, just like any other data in Python, class definitions can also be modified. Any modifications to attributes in a class definition will be seen in any instances of that definition, so long as that instance hasn't overridden the attribute that you're modifying.

>>> def DeAbbreviate(sequence_container):
...     sequence_container.length = sequence_container.len
...     del sequence_container.len
>>> DeAbbreviate(container_class)
>>> wrapped_string.length()
>>> wrapped_string.len()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: String instance has no attribute 'len'

You can also delete class definitions, but that will not affect instances of the class.

>>> del container_class
>>> wrapped_string2 = container_class()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'container_class' is not defined
>>> wrapped_string.length()

The type MetaclassEdit

The metaclass for all standard Python types is the "type" object.

>>> type(object)
<type 'type'>
>>> type(int)
<type 'type'>
>>> type(list)
<type 'type'>

Just like list, int and object, "type" is itself a normal Python object, and is itself an instance of a class. In this case, it is in fact an instance of itself.

>>> type(type)
<type 'type'>

It can be instantiated to create new class objects similarly to the class factory example above by passing the name of the new class, the base classes to inherit from, and a dictionary defining the namespace to use.

For instance, the code:

>>> class MyClass(BaseClass):
...     attribute = 42

Could also be written as:

>>> MyClass = type("MyClass", (BaseClass,), {'attribute' : 42})


It is possible to create a class with a different metaclass than type by setting the metaclass keyword argument when defining the class. When this is done, the class, and its subclass will be created using your custom metaclass. For example

class CustomMetaclass(type):
    def __init__(cls, name, bases, dct):
        print "Creating class %s using CustomMetaclass" % name
        super(CustomMetaclass, cls).__init__(name, bases, dct)

class BaseClass(metaclass=CustomMetaclass):

class Subclass1(BaseClass):

This will print

Creating class BaseClass using CustomMetaclass
Creating class Subclass1 using CustomMetaclass

By creating a custom metaclass in this way, it is possible to change how the class is constructed. This allows you to add or remove attributes and methods, register creation of classes and subclasses creation and various other manipulations when the class is created.

More resourcesEdit