En Python, ¿qué son las metaclases y para qué las usamos?
Una metaclase es la clase de una clase. Una clase define cómo se comporta una instancia de la clase (es decir, un objeto), mientras que una metaclase define cómo se comporta una clase. Una clase es una instancia de una metaclase.
Mientras que en Python puede usar llamadas arbitrarias para metaclases (como muestra Jerub ), el mejor enfoque es convertirlo en una clase real. typees la metaclase habitual en Python. typees en sí mismo una clase, y es su propio tipo. No podrá recrear algo como typepuramente en Python, pero Python hace un poco de trampa. Para crear su propia metaclase en Python, realmente solo desea crear una subclase type.
Una metaclase se usa más comúnmente como una fábrica de clases. Cuando crea un objeto llamando a la clase, Python crea una nueva clase (cuando ejecuta la instrucción 'clase') llamando a la metaclase. En combinación con los métodos normales __init__y __new__, las metaclases le permiten hacer 'cosas adicionales' al crear una clase, como registrar la nueva clase con algún registro o reemplazar la clase con algo completamente diferente.
Cuando classse ejecuta la declaración, Python primero ejecuta el cuerpo de la classdeclaración como un bloque de código normal. El espacio de nombres resultante (un dictado) contiene los atributos de la futura clase. La metaclase se determina mirando las clases base de la futura clase (las metaclases se heredan), el __metaclass__atributo de la futura clase (si existe) o la __metaclass__variable global. Luego se llama a la metaclase con el nombre, las bases y los atributos de la clase para instanciarla.
Sin embargo, las metaclases en realidad definen el tipo de una clase, no solo una fábrica para ella, por lo que puede hacer mucho más con ellas. Puede, por ejemplo, definir métodos normales en la metaclase. Estos métodos de metaclase son como métodos de clase en el sentido de que se pueden llamar en la clase sin una instancia, pero tampoco son como métodos de clase en el sentido de que no se pueden llamar en una instancia de la clase. type.__subclasses__()es un ejemplo de un método en la typemetaclase. También puede definir los métodos 'mágicos' normales, como __add__, __iter__y __getattr__, para implementar o cambiar el comportamiento de la clase.
Aquí hay un ejemplo agregado de los bits y piezas:
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__