O que é uma metaclasse no Python?

Uma metaclasse é a classe de uma classe. Como uma classe define como uma instância da classe se comporta, uma metaclasse define como uma classe se comporta. Uma classe é uma instância de uma metaclasse.

metaclass diagram

Enquanto em Python você pode usar arbitrários callables para metaclasses (como Jerub mostra), a abordagem mais útil é realmente torná-lo uma classe real em si. tipo é a metaclasse usual em Python. No caso de você se perguntar, sim, type é em si uma classe, e é seu próprio tipo. Você não poderá recriar algo como type puramente em Python, mas a Python engana um pouco. Para criar sua própria metaclasse em Python, você realmente quer apenas subclasse type.

Uma metaclasse é mais comumente usada como uma classe-fábrica. Como você cria uma instância da classe ao chamar a classe, o Python cria uma nova classe (quando executa a instrução ‘class’) chamando a metaclass. Combinado com o normal __init__ e __new__ Métodos, metaclasses, portanto, permitem que você faça “coisas extras” ao criar uma classe, como registrar a nova classe com algum registro, ou mesmo substituir a classe por outra coisa inteira.

Quando a class A declaração é executada, o Python primeiro executa o corpo do class declaração como um bloco de código normal. O namespace resultante (a dict) contém os atributos da classe-a-ser. A metaclasse é determinada olhando os baseclasses da classe-a-ser (as metaclasses são herdadas), no __metaclass__ atributo da classe-a-ser (se houver) ou a __metaclass__ variável global. A metaclasse é então chamada com o nome, bases e atributos da classe para instanciá-lo.

No entanto, as metaclasses realmente definem o type de uma class, não apenas uma fábrica, para que você possa fazer muito mais com eles. Você pode, por exemplo, definir métodos normais na metaclasse. Esses métodos de metaclasse são como métodos de classe, na medida em que eles podem ser chamados na classe sem uma instância, mas também não são como métodos de classe na medida em que não podem ser chamados de uma instância da classe. type.__subclasses__() é um exemplo de um método no type metaclass. Você também pode definir os métodos “mágicos” normais, como __add____iter__ and __getattr__, para implementar ou alterar a forma como a classe se comporta.

Aqui está um exemplo agregado dos bits e peças:

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

class MyType(type):
    def __new__(cls, 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, cls).__new__(cls, 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__
· · ·

Junte-se a nós e esteja sempre atualizado com as últimas novidades e dicas