Curso
Una metaclase en Python es la clase de una clase: define cómo se comporta una clase. Una clase, a su vez, es una instancia de una metaclase. En Python, una clase define cómo se comportarán las instancias de esa clase. Para entender bien las metaclases, conviene tener experiencia previa trabajando con clases en Python. Antes de profundizar, despejemos algunos conceptos.
En Python, todo es un objeto
class TestClass():
pass
my_test_class = TestClass()
print(my_test_class)
<__main__.TestClass object at 0x7f6fcc6bf908>
Las clases en Python se pueden crear dinámicamente
type en Python nos permite conocer el tipo de un objeto. Probemos con el objeto que acabamos de crear.
type(TestClass)
type
type(type)
type
Espera, ¿qué ha pasado? Podríamos esperar que el tipo del objeto que creamos arriba fuese class, pero no lo es. Quédate con esa idea un momento; lo veremos en un instante. También observamos que el tipo de type es type. Es una instancia de type. Otra cosa "mágica" que hace type es permitirnos crear clases dinámicamente. Veamos cómo. La clase DataCamp de abajo podría crearse así usando type:
class DataCamp():
pass
DataCampClass = type('DataCamp', (), {})
print(DataCampClass)
print(DataCamp())
<class '__main__.DataCamp'>
<__main__.DataCamp object at 0x7f6fcc66e358>
En el ejemplo anterior, DataCamp es el nombre de la clase, mientras que DataCampClass es la variable que guarda la referencia a la clase. Al usar type podemos pasar atributos de la clase mediante un diccionario, como se muestra a continuación:
PythonClass = type('PythonClass', (), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass.start_date, PythonClass.instructor)
print(PythonClass)
August 2018 John Doe
<class '__main__.PythonClass'>
Si quisiéramos que nuestra PythonClass heredase de la clase DataCamp, la pasamos como segundo argumento al definir la clase con type:
PythonClass = type('PythonClass', (DataCamp,), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass)
<class '__main__.PythonClass'>
Con estos dos conceptos claros, vemos que Python crea las clases usando una metaclase. Ya hemos dicho que todo en Python es un objeto; esos objetos los crean metaclases. Cada vez que usamos class para crear una clase, hay una metaclase que hace el trabajo entre bambalinas. Ya hemos visto a type hacerlo en la práctica. Es parecido a str, que crea cadenas, e int, que crea enteros. En Python, el atributo ___class__ nos permite comprobar el tipo de la instancia actual. Creamos una cadena y miramos su tipo:
article = 'metaclasses'
article.__class__
str
También podemos consultarlo con type(article).
type(article)
str
Si comprobamos el tipo de str, veremos que también es type.
type(str)
type
Si comprobamos el tipo de float, int, list, tuple y dict, obtendremos un resultado similar. Esto es porque todos estos objetos son de tipo type.
print(type(list),type(float), type(dict), type(tuple))
<class 'type'> <class 'type'> <class 'type'> <class 'type'>
Ya hemos visto que type crea clases. Por tanto, si miramos el __class__ de __class__, debería devolver type.
article.__class__.__class__
type
Domina tus habilidades de datos con DataCamp
Más de 10 millones de personas aprenden Python, R, SQL y otras habilidades tecnológicas con nuestros cursos prácticos elaborados por expertos del sector.

Crear metaclases personalizadas
En Python, podemos personalizar el proceso de creación de clases pasando la palabra clave metaclass en la definición de la clase. También puede hacerse heredando de una clase que ya haya definido esta palabra clave.
class MyMeta(type):
pass
class MyClass(metaclass=MyMeta):
pass
class MySubclass(MyClass):
pass
Como puedes ver abajo, el tipo de la clase MyMeta es type y el tipo de MyClass y MySubClass es MyMeta.
print(type(MyMeta))
print(type(MyClass))
print(type(MySubclass))
<class 'type'>
<class '__main__.MyMeta'>
<class '__main__.MyMeta'>
Si al definir una clase no se especifica metaclase, se usará por defecto la metaclase type. Si se indica una metaclase y no es una instancia de type(), entonces se usa directamente como metaclase.
__new__ y __init__
Las metaclases también pueden definirse de dos formas, como se muestra a continuación. Explicamos la diferencia enseguida.
class MetaOne(type):
def __new__(cls, name, bases, dict):
pass
class MetaTwo(type):
def __init__(self, name, bases, dict):
pass
__new__ se usa cuando quieres definir el diccionario o la tupla de bases antes de que se cree la clase. El valor de retorno de __new__ suele ser una instancia de cls. __new__ permite a las subclases de tipos inmutables personalizar la creación de instancias y puede sobreescribirse en metaclases personalizadas para ajustar la creación de clases. __init__ se llama normalmente después de que el objeto se haya creado para inicializarlo.
Método __call__ de la metaclase
Según la documentación oficial, también podemos sobreescribir otros métodos de clase definiendo un método __call__() personalizado en la metaclase que permita un comportamiento propio cuando se llama a la clase.
Método __prepare__ de la metaclase
Según el modelo de datos de Python
Una vez identificada la metaclase adecuada, se prepara el espacio de nombres de la clase. Si la metaclase tiene un atributo __prepare__, se llama como namespace = metaclass.__prepare__(name, bases, **kwds) (donde los argumentos con nombre adicionales, si los hay, provienen de la definición de la clase). Si la metaclase no tiene atributo __prepare__, el espacio de nombres de la clase se inicializa como una asignación ordenada vacía. - docs.python.org
Patrón singleton con una metaclase
Es un patrón de diseño que restringe la instanciación de una clase a un único objeto. Puede ser útil, por ejemplo, al diseñar una clase de conexión a base de datos: quizá quieras tener una sola instancia de la clase de conexión.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta,cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
pass
Conclusión
En este artículo has aprendido qué son las metaclases y cómo implementarlas en tus programas en Python. Las metaclases pueden aplicarse, entre otros usos, al registro de clases en el momento de su creación, al registro de logs y al perfilado. Son conceptos bastante abstractos y quizá te preguntes si realmente necesitas usarlos. El veterano pythonista Tim Peters lo resume muy bien.
"Las metaclases son una magia más profunda de la que el 99% de los usuarios debería preocuparse. Si te preguntas si las necesitas, no las necesitas (las personas que realmente las necesitan lo saben con certeza y no necesitan que se les explique por qué)." - realpython
Si quieres seguir aprendiendo Python, empieza el itinerario de habilidades Python Programming de DataCamp y echa un vistazo a nuestro tutorial sobre clases en Python.