None

Python Metaclasses

April 28, 2010

When you create a class in python, the mechanism used comes from a class called type. It is possible to subclass from type and change the create class behaviour.

This example is taken from the Django model form. The model form automatically creates attributes on itself from the model object it is linked to.

class ModelFormMetaclass(type):
    def __new__(cls, name, bases, attrs):
        formfield_callback = attrs.pop('formfield_callback',
                lambda f: f.formfield())
        try:
            parents = [b for b in bases if issubclass(b, ModelForm)]
        except NameError:
            # We are defining ModelForm itself.
            parents = None
        declared_fields = get_declared_fields(bases, attrs, False)
        new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases, attrs)
        if not parents:
            return new_class

        if 'media' not in attrs:
            new_class.media = media_property(new_class)
        opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
        if opts.model:
            # If a model is defined, extract form fields from it.
            fields = fields_for_model(opts.model, opts.fields,
                                      opts.exclude, formfield_callback)
            # Override default model fields with any custom declared ones
            # (plus, include all the other declared fields).
            fields.update(declared_fields)
        else:
            fields = declared_fields
        new_class.declared_fields = declared_fields
        new_class.base_fields = fields
        return new_class

This is then used using:

class ModelForm(BaseModelForm):
    __metaclass__ = ModelFormMetaclass

and this ModelForm is then used for the superclass of specific ModelForms in your application.

The metaclass changes the object creation process. The new function is passed the metaclass itself (conventionally called cls not self), the name of the new class, the superclasses, and the attributes defined. It looks through the classes, adds on the fields from the related model, and then returns the new class.

References

Tags: python metaclass