What are metaclasses in Python?

What are metaclasses? What are they made use of for?

6854
2022-07-04 17:16:10
Source Share
Answers: 4

I think the ONLamp introduction to metaclass programming is well written and gives a really good introduction to the topic despite being several years old already.

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (archived at https://web.archive.org/web/20080206005253/http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html)

In short: A class is a blueprint for the creation of an instance, a metaclass is a blueprint for the creation of a class. It can be easily seen that in Python classes need to be first-class objects too to enable this behavior.

I've never written one myself, but I think one of the nicest uses of metaclasses can be seen in the Django framework. The model classes use a metaclass approach to enable a declarative style of writing new models or form classes. While the metaclass is creating the class, all members get the possibility to customize the class itself.

The thing that's left to say is: If you don't know what metaclasses are, the probability that you will not need them is 99%.

157
2022-07-04 18:56:56
Source

Note, this answer is for Python 2.x as it was written in 2008, metaclasses are slightly different in 3.x.

Metaclasses are the secret sauce that make 'class' work. The default metaclass for a new style object is called 'type'.

class type(object)
  |  type(object) -> the object's type
  |  type(name, bases, dict) -> a new type

Metaclasses take 3 args. 'name', 'bases' and 'dict'

Here is where the secret starts. Look for where name, bases and the dict come from in this example class definition.

class ThisIsTheName(Bases, Are, Here):
    All_the_code_here
    def doesIs(create, a):
        dict

Lets define a metaclass that will demonstrate how 'class:' calls it.

def test_metaclass(name, bases, dict):
    print 'The Class Name is', name
    print 'The Class Bases are', bases
    print 'The dict has', len(dict), 'elems, the keys are', dict.keys()

    return "yellow"

class TestName(object, None, int, 1):
    __metaclass__ = test_metaclass
    foo = 1
    def baz(self, arr):
        pass

print 'TestName = ', repr(TestName)

# output => 
The Class Name is TestName
The Class Bases are (<type 'object'>, None, <type 'int'>, 1)
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName =  'yellow'

And now, an example that actually means something, this will automatically make the variables in the list "attributes" set on the class, and set to None.

def init_attributes(name, bases, dict):
    if 'attributes' in dict:
        for attr in dict['attributes']:
            dict[attr] = None

    return type(name, bases, dict)

class Initialised(object):
    __metaclass__ = init_attributes
    attributes = ['foo', 'bar', 'baz']

print 'foo =>', Initialised.foo
# output=>
foo => None

Note that the magic behaviour that Initialised gains by having the metaclass init_attributes is not passed onto a subclass of Initialised.

Here is an even more concrete example, showing how you can subclass 'type' to make a metaclass that performs an action when the class is created. This is quite tricky:

class MetaSingleton(type):
    instance = None
    def __call__(cls, *args, **kw):
        if cls.instance is None:
            cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
        return cls.instance

class Foo(object):
    __metaclass__ = MetaSingleton

a = Foo()
b = Foo()
assert a is b
473
2022-07-04 18:56:53
Source

One usage for metaclasses is including new buildings and also approaches to an instance instantly.

As an example, if you consider Django models, their definition looks a little bit complex. It seems you are just specifying class properties:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

However, at runtime the Person things are loaded with all type of valuable approaches. See the source for some impressive metaclassery.

194
2022-07-04 18:04:28
Source

A metaclass is the class of a class. A class specifies just how an instance of the class (i.e. an object) acts while a metaclass specifies just how a class acts. A class is an instance of a metaclass.

While in Python you can make use of approximate callables for metaclasses (like Jerub programs), the far better strategy is to make it a real class itself. type is the common metaclass in Python. type is itself a class, and also it is its very own type. You will not have the ability to recreate something like type totally in Python, yet Python rips off a little. To create your very own metaclass in Python you actually simply intend to subclass type.

A metaclass is most generally made use of as a class - manufacturing facility. When you create an object by calling the class, Python develops a new class (when it implements the 'class' declaration) by calling the metaclass. Incorporated with the regular __init__ and also __new__ approaches, metaclasses consequently permit you to do 'added points' when developing a class, like signing up the new class with some computer system registry or change the class with another thing totally.

When the class declaration is implemented, Python first implements the body of the class declaration as a regular block of code. The resulting namespace (a dict) holds the features of the class - to - be. The metaclass is established by considering the baseclasses of the class - to - be (metaclasses are acquired), at the __metaclass__ feature of the class - to - be (if any kind of) or the __metaclass__ international variable. The metaclass is after that called with the name, bases and also features of the class to instantiate it.

Nonetheless, metaclasses in fact specify the type of a class, not simply a manufacturing facility for it, so you can do far more with them. You can, as an example, specify regular approaches on the metaclass. These metaclass - approaches resemble classmethods because they can be gotten in touch with the class without an instance, yet they are additionally not such as classmethods because they can not be gotten in touch with an instance of the class. type.__subclasses__() is an instance of a method on the type metaclass. You can additionally specify the regular 'magic' approaches, like __add__, __iter__ and also __getattr__, to implement or transform just how the class acts.

Below is an aggregated instance of the little bits and also pieces:

def make_hook(f):
    """Decorator to turn 'foo' method into '__foo__'"""
    f.is_hook = 1
    return f

class MyType(type):
    def __new__(mcls, name, bases, attrs):

        if name.startswith('None'):
            return None

        # Go over attributes and see if they should be renamed.
        newattrs = {}
        for attrname, attrvalue in attrs.iteritems():
            if getattr(attrvalue, 'is_hook', 0):
                newattrs['__%s__' % attrname] = attrvalue
            else:
                newattrs[attrname] = attrvalue

        return super(MyType, mcls).__new__(mcls, name, bases, newattrs)

    def __init__(self, name, bases, attrs):
        super(MyType, self).__init__(name, bases, attrs)

        # classregistry.register(self, self.interfaces)
        print "Would register class %s now." % self

    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass
        # Alternatively, to autogenerate the classname as well as the class:
        # return type(self.__name__ + other.__name__, (self, other), {})

    def unregister(self):
        # classregistry.unregister(self)
        print "Would unregister class %s now." % self

class MyObject:
    __metaclass__ = MyType


class NoneSample(MyObject):
    pass

# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)

class Example(MyObject):
    def __init__(self, value):
        self.value = value
    @make_hook
    def add(self, other):
        return self.__class__(self.value + other.value)

# Will unregister the class
Example.unregister()

inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()

print inst + inst
class Sibling(MyObject):
    pass

ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
3381
2022-07-04 18:00:48
Source