() translation by (you can also view the original English article)
Este consejo rápido ofrece una breve descripción de lo que queremos decir cuando hablamos de una metaclase en Python y muestra algunos ejemplos del concepto.
Antes de profundizar en este artículo, debo señalar un punto importante sobre las clases en Python que nos facilita la comprensión del concepto de metaclases.
¡¿Una clase es un objeto en Python?!
Si has usado un lenguaje de programación diferente a Python, el concepto que entendiste sobre las clases muy probablemente sea que estas son una forma de crear nuevos objetos. Esto también es cierto en Python, pero Python incluso va un paso más adelante: ¡las clases también son consideradas objetos!
Entonces, si creaste la siguiente clase en Python:
1 |
class myClass(object): |
2 |
pass
|
Esto simplemente significa que un objeto con el nombre myClass
ha sido creado en la memoria. Ya que este objeto es capaz de crear nuevos objetos, se considera una clase. Esto significa que podemos aplicar operaciones de objetos a las clases en Python, ya que las clases por sí mismas son objetos.
Por lo tanto, podemos realizar operaciones en clases como asignar la clase a una variable, de la siguiente manera:
1 |
class_object = myClass() |
2 |
print class_object |
Lo que devuelve:
1 |
<__main__.myClass object at 0x102623610> |
Incluso puedes enviar la clase myClass
como parámetro a un método, de la siguiente forma:
1 |
def class_object(object): |
2 |
print object |
3 |
|
4 |
class_object(myClass) |
Lo que devuelve el siguiente resultado:
1 |
<class '__main__.myClass'> |
Además de otras operaciones que normalmente puedes aplicar a los objetos.
Metaclases
¿Tal vez te hayas encontrado con la palabra clave type
en Python? Lo más probable es que la hayas usado para verificar el tipo de algún objeto, como se muestra en los siguientes ejemplos:
1 |
print type('abder') |
2 |
print type(100) |
3 |
print type(100.0) |
4 |
print type(int) |
En cuyo caso obtendrías el siguiente resultado:
1 |
<type 'str'> |
2 |
<type 'int'> |
3 |
<type 'float'> |
4 |
<type 'type'> |
Mirando el resultado, todo parece bastante claro hasta que llegas al tipo type
. Para ver lo que esto podría significar, regresemos a nuestra clase que definimos al principio de este artículo:
1 |
class myClass(object): |
2 |
pass
|
Ahora haz lo siguiente:
1 |
print type(myClass) |
¿Cuál sería el resultado de esta sentencia? Sorprendentemente será:
1 |
<type 'type'> |
Siendo así, podemos concluir que el tipo de las clases en Python ¡es type
!
¿Cuál es la relación entre un tipo type
y una metaclase metaclass
? Bueno, un tipo type
es una metaclase metaclass
, siempre y cuando la metaclase metaclass
predeterminada sea type
. Se que esto puede ser confuso, especialmente ya que type
puede usarse para devolver la clase de algún objeto como se muestra arriba, pero esto se debe a la compatibilidad retroactiva en Python. Entonces, si escribes:
1 |
print type(type) |
Obtendrás:
1 |
<type 'type'> |
¡Lo que significa que un tipo type
es de tipo type
!
El término metaclass
simplemente hace referencia a algo usado para crear clases. En otras palabras, es la clase de una clase, lo que significa que la instancia de una clase en este caso es una clase. Por lo tanto, type
se considera una metaclass
, ya que la instancia de un type
es una clase.
Por ejemplo, cuando mencionamos anteriormente la sentencia a continuación:
1 |
class_object = myClass() |
Esto simplemente crea un objeto o instancia de la clase myClass
. En otras palabras, usamos una clase para crear un objeto.
De la misma forma, cuando hicimos lo siguiente:
1 |
class myClass(object): |
2 |
pass
|
La meteclass
fue usada para crear la clase myClass
(que se considera un type
). Entonces, de la misma forma en la que un objeto es una instancia de una clase, una clase es una instancia de una metaclass
.
Usando metaclass para crear una clase
En esta sección, vamos a ver cómo podemos usar una metaclass
para crear una clase, en vez de usar la sentencia class
como lo vimos en el tutorial sobre clases y objetos. Como vimos anteriormente, la metaclass
predeterminada es type
. Por lo tanto, podemos usar la siguiente sentencia para crear una nueva clase:
1 |
new_class = type('myClass',(),{}) |
Si quieres simplificar las cosas, puedes asignar el mismo nombre de clase myClass
al nombre de la variable.
Aquí, el diccionario { }
se usa para definir los atributos de la clase. Entonces, tener la siguiente sentencia:
1 |
myClass = type('myClass',(),{'a':True}) |
Es similar a:
1 |
class myClass(object): |
2 |
a = True |
El atributo __metaclass__
Digamos que creamos la clase myClass
de la siguiente forma:
1 |
class myClass(object): |
2 |
__metaclass__ = myMetaClass |
3 |
pass
|
En este caso, la creación de la clase ocurrirá usando myMetaClass
en vez de type
, de la siguiente forma:
1 |
myClass = myMetaClass(className, bases, dictionary) |
Creación e inicialización de una metaclase
Si quieres tener control sobre cómo crear e inicializar una clase después de su creación, simplemente puedes usar el método __new__
y el constructor __init__
de la metaclase, respectivamente. Entonces, al llamar a myMetaClass
que se muestra arriba, esto es lo que sucederá en segundo plano:
1 |
myClass = myMetaClass.__new__(myMetaClass, name, bases, dictionary) |
2 |
myMetaClass.__init__(myClass, name, bases, dictionary) |
No quiero alargar más este consejo rápido, pero para resumir, podemos concluir que una metaclass
en Python se usa para crear una clase. Es decir, la instancia de una metaclass
es una clase. Si quieres profundizar en el tema de las metaclases, puedes consultar este tutorial.