En Python, ¿qué son las metaclases y para qué las usamos?
fuente
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 callables arbitrarios para metaclases (como muestra Jerub ), el mejor enfoque es convertirlo en una clase real. type
es la metaclase habitual en Python. type
es en sí misma una clase, y es su propio tipo. No podrá recrear algo como type
puramente en Python, pero Python hace trampa un poco. Para crear su propia metaclase en Python, realmente solo desea subclasificar 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 lo normal __init__
y los __new__
métodos, las metaclases por lo tanto 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 class
se ejecuta la declaración, Python primero ejecuta el cuerpo de la class
declaración como un bloque de código normal. El espacio de nombres resultante (un dict) contiene los atributos de la futura clase. La metaclase se determina al observar las clases base de la futura clase (las metaclases se heredan), el __metaclass__
atributo de la futura clase (si corresponde) o la __metaclass__
variable global. La metaclase se llama 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 invocar en la clase sin una instancia, pero tampoco son como los métodos de clase en que no se pueden invocar en una instancia de la clase. type.__subclasses__()
es un ejemplo de un método en la type
metaclase. 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__
class A(type):pass<NEWLINE>class B(type,metaclass=A):pass<NEWLINE>b.__class__ = b
__metaclass__
no es compatible con Python 3. En el uso de Python 3class MyObject(metaclass=MyType)
, consulte python.org/dev/peps/pep-3115 y la respuesta a continuación.Clases como objetos
Antes de comprender las metaclases, debe dominar las clases en Python. Y Python tiene una idea muy peculiar de qué clases son, tomadas del lenguaje Smalltalk.
En la mayoría de los idiomas, las clases son solo piezas de código que describen cómo producir un objeto. Eso también es cierto en Python:
Pero las clases son más que eso en Python. Las clases también son objetos.
Si, objetos.
Tan pronto como use la palabra clave
class
, Python la ejecuta y crea un OBJETO. La instruccióncrea en la memoria un objeto con el nombre "ObjectCreator".
Este objeto (la clase) es capaz de crear objetos (las instancias), y es por eso que es una clase .
Pero aún así, es un objeto, y por lo tanto:
p.ej:
Crear clases dinámicamente
Como las clases son objetos, puede crearlos sobre la marcha, como cualquier objeto.
Primero, puede crear una clase en una función usando
class
:Pero no es tan dinámico, ya que todavía tienes que escribir toda la clase tú mismo.
Como las clases son objetos, deben ser generadas por algo.
Cuando usa la
class
palabra clave, Python crea este objeto automáticamente. Pero como con la mayoría de las cosas en Python, le brinda una forma de hacerlo manualmente.¿Recuerdas la función
type
? La función antigua que le permite saber de qué tipo es un objeto:Bueno,
type
tiene una habilidad completamente diferente, también puede crear clases sobre la marcha.type
puede tomar la descripción de una clase como parámetros y devolver una clase.(Lo sé, es una tontería que la misma función pueda tener dos usos completamente diferentes según los parámetros que le pases. Es un problema debido a la compatibilidad con versiones anteriores en Python)
type
funciona de esta manera:Dónde:
name
: nombre de la clasebases
: tupla de la clase padre (por herencia, puede estar vacía)attrs
: diccionario que contiene nombres y valores de atributosp.ej:
se puede crear manualmente de esta manera:
Notarás que usamos "MyShinyClass" como el nombre de la clase y como la variable para contener la referencia de clase. Pueden ser diferentes, pero no hay razón para complicar las cosas.
type
acepta un diccionario para definir los atributos de la clase. Entonces:Se puede traducir a:
Y se usa como una clase normal:
Y, por supuesto, puedes heredar de él, así que:
sería:
Eventualmente querrás agregar métodos a tu clase. Simplemente defina una función con la firma adecuada y asígnela como un atributo.
Y puede agregar aún más métodos después de crear dinámicamente la clase, al igual que agregar métodos a un objeto de clase creado normalmente.
Verá a dónde vamos: en Python, las clases son objetos, y puede crear una clase sobre la marcha, dinámicamente.
Esto es lo que hace Python cuando usa la palabra clave
class
, y lo hace usando una metaclase.¿Qué son las metaclases (finalmente)
Las metaclases son las 'cosas' que crean clases.
Define clases para crear objetos, ¿verdad?
Pero aprendimos que las clases de Python son objetos.
Bueno, las metaclases son las que crean estos objetos. Son las clases de las clases, puedes imaginarlas de esta manera:
Has visto que eso
type
te permite hacer algo como esto:Es porque la función
type
es de hecho una metaclase.type
es la metaclase que Python usa para crear todas las clases detrás de escena.Ahora te preguntas por qué diablos está escrito en minúsculas, y no
Type
.Bueno, supongo que es una cuestión de coherencia con
str
la clase que crea objetos de cadenas yint
la clase que crea objetos enteros.type
es solo la clase que crea objetos de clase.Puede ver eso al verificar el
__class__
atributo.Todo, y quiero decir todo, es un objeto en Python. Eso incluye entradas, cadenas, funciones y clases. Todos ellos son objetos. Y todos ellos han sido creados a partir de una clase:
Ahora, ¿cuál es el
__class__
de alguno__class__
?Entonces, una metaclase es solo lo que crea objetos de clase.
Puede llamarlo una "fábrica de clase" si lo desea.
type
es la metaclase incorporada que utiliza Python, pero, por supuesto, puede crear su propia metaclase.El
__metaclass__
atributoEn Python 2, puede agregar un
__metaclass__
atributo cuando escribe una clase (consulte la siguiente sección para la sintaxis de Python 3):Si lo hace, Python usará la metaclase para crear la clase
Foo
.Cuidado, es complicado.
class Foo(object)
Primero escribe , pero el objeto de clase aúnFoo
no se ha creado en la memoria.Python buscará
__metaclass__
en la definición de clase. Si lo encuentra, lo usará para crear la clase de objetoFoo
. Si no es así, se usarátype
para crear la clase.Lee eso varias veces.
Cuando tu lo hagas:
Python hace lo siguiente:
¿Hay un
__metaclass__
atributo enFoo
?En caso afirmativo, cree en la memoria un objeto de clase (dije un objeto de clase, quédese conmigo aquí), con el nombre
Foo
usando lo que está en__metaclass__
.Si Python no puede encontrar
__metaclass__
, buscará un__metaclass__
nivel MÓDULO e intentará hacer lo mismo (pero solo para las clases que no heredan nada, básicamente las clases de estilo antiguo).Luego, si no puede encontrar ninguno
__metaclass__
, usará laBar
metaclase propia (la primera matriz) (que podría ser la predeterminadatype
) para crear el objeto de clase.Tenga cuidado aquí de que el
__metaclass__
atributo no se heredará, la metaclase del padre (Bar.__class__
) sí. Si seBar
usa un__metaclass__
atributo que se creóBar
contype()
(y notype.__new__()
), las subclases no heredarán ese comportamiento.Ahora la gran pregunta es, ¿qué puedes poner
__metaclass__
?La respuesta es: algo que puede crear una clase.
¿Y qué puede crear una clase?
type
, o cualquier cosa que lo subclasifique o lo use.Metaclases en Python 3
La sintaxis para establecer la metaclase ha cambiado en Python 3:
es decir, el
__metaclass__
atributo ya no se usa, a favor de un argumento de palabra clave en la lista de clases base.Sin embargo, el comportamiento de las metaclases se mantiene prácticamente igual .
Una cosa agregada a las metaclases en python 3 es que también puede pasar atributos como argumentos de palabras clave a una metaclase, de esta manera:
Lea la sección a continuación para ver cómo Python maneja esto.
Metaclases personalizadas
El objetivo principal de una metaclase es cambiar la clase automáticamente, cuando se crea.
Por lo general, hace esto para las API, donde desea crear clases que coincidan con el contexto actual.
Imagine un ejemplo estúpido, donde decide que todas las clases en su módulo deben tener sus atributos escritos en mayúsculas. Hay varias formas de hacer esto, pero una es configurarlo
__metaclass__
a nivel de módulo.De esta manera, todas las clases de este módulo se crearán usando esta metaclase, y solo tenemos que decirle a la metaclase que convierta todos los atributos en mayúsculas.
Afortunadamente, en
__metaclass__
realidad puede ser invocable, no necesita ser una clase formal (lo sé, algo con 'clase' en su nombre no necesita ser una clase, imagínate ... pero es útil).Entonces comenzaremos con un ejemplo simple, usando una función.
Vamos a revisar:
Ahora, hagamos exactamente lo mismo, pero usando una clase real para una metaclase:
Reescribamos lo anterior, pero con nombres de variables más cortos y realistas ahora que sabemos lo que significan:
Es posible que haya notado el argumento adicional
cls
. No tiene nada de especial:__new__
siempre recibe la clase en la que se define, como primer parámetro. Al igual que tieneself
para los métodos ordinarios que reciben la instancia como primer parámetro, o la clase definitoria para los métodos de clase.Pero esto no es una OOP adecuada. Estamos llamando
type
directamente y no estamos anulando o llamando a los padres__new__
. Hagamos eso en su lugar:Podemos hacerlo aún más limpio mediante el uso
super
, lo que facilitará la herencia (porque sí, puede tener metaclases, heredar de metaclases, heredar de tipo):Ah, y en Python 3 si haces esta llamada con argumentos de palabras clave, así:
Se traduce a esto en la metaclase para usarlo:
Eso es. Realmente no hay nada más sobre las metaclases.
La razón detrás de la complejidad del código que usa metaclases no se debe a las metaclases, sino a que usualmente usas metaclases para hacer cosas retorcidas que dependen de la introspección, la manipulación de la herencia, variables como
__dict__
, etc.De hecho, las metaclases son especialmente útiles para hacer magia negra y, por lo tanto, cosas complicadas. Pero por sí mismos, son simples:
¿Por qué usarías clases de metaclases en lugar de funciones?
Dado que
__metaclass__
puede aceptar cualquier invocable, ¿por qué usaría una clase ya que obviamente es más complicada?Hay varias razones para hacerlo:
UpperAttrMetaclass(type)
, sabes lo que va a seguir__new__
,__init__
y__call__
. Lo que te permitirá hacer cosas diferentes. Incluso si generalmente puede hacerlo todo__new__
, algunas personas se sienten más cómodas de usar__init__
.¿Por qué usarías metaclases?
Ahora la gran pregunta. ¿Por qué usaría alguna característica oscura propensa a errores?
Bueno, generalmente no:
Python Guru Tim Peters
El caso de uso principal para una metaclase es crear una API. Un ejemplo típico de esto es el Django ORM. Le permite definir algo como esto:
Pero si haces esto:
No devolverá un
IntegerField
objeto. Devolverá unint
e incluso puede tomarlo directamente de la base de datos.Esto es posible porque
models.Model
define__metaclass__
y utiliza algo de magia que convertirá loPerson
que acaba de definir con declaraciones simples en un enlace complejo a un campo de base de datos.Django hace que algo complejo parezca simple al exponer una API simple y usar metaclases, recreando el código de esta API para hacer el trabajo real detrás de escena.
La última palabra
Primero, sabe que las clases son objetos que pueden crear instancias.
Bueno, de hecho, las clases son en sí mismas instancias. De metaclases.
Todo es un objeto en Python, y todos son instancias de clases o instancias de metaclases.
A excepción de
type
.type
es en realidad su propia metaclase. Esto no es algo que pueda reproducir en Python puro, y se hace haciendo trampa un poco a nivel de implementación.En segundo lugar, las metaclases son complicadas. Es posible que no desee usarlos para alteraciones de clase muy simples. Puede cambiar las clases utilizando dos técnicas diferentes:
El 99% del tiempo que necesita una alteración de clase, es mejor usarlos.
Pero el 98% del tiempo, no necesita alteración de clase en absoluto.
fuente
models.Model
no usa__metaclass__
sino más bienclass Model(metaclass=ModelBase):
para hacer referencia a unaModelBase
clase que luego hace la magia de metaclase antes mencionada. ¡Buena publicación! Aquí está la fuente de Django: github.com/django/django/blob/master/django/db/models/…__metaclass__
atributo no se heredará, la metaclase del padre (Bar.__class__
) sí. Si seBar
usa un__metaclass__
atributo que se creóBar
contype()
(y notype.__new__()
), las subclases no heredarán ese comportamiento. >> - ¿Podría usted / alguien explicar un poco más este pasaje?Now you wonder why the heck is it written in lowercase, and not Type?
- bueno porque está implementado en C - es la misma razón por la cual defaultdict es minúscula mientras que OrderedDict (en python 2) es normal CamelCaseTenga en cuenta que esta respuesta es para Python 2.x como se escribió en 2008, las metaclases son ligeramente diferentes en 3.x.
Las metaclases son la salsa secreta que hace que la 'clase' funcione. La metaclase predeterminada para un nuevo objeto de estilo se llama 'tipo'.
Las metaclases toman 3 args. ' nombre ', ' bases ' y ' dict '
Aquí es donde comienza el secreto. Busque de dónde provienen el nombre, las bases y el dict en esta definición de clase de ejemplo.
Vamos a definir una metaclase que demostrará cómo ' clase: ' lo llama.
Y ahora, un ejemplo que realmente significa algo, esto automáticamente hará que las variables en la lista de "atributos" se establezcan en la clase y se establezcan en Ninguno.
Tenga en cuenta que el comportamiento mágico que
Initialised
gana al tener la metaclaseinit_attributes
no se pasa a una subclase deInitialised
.Aquí hay un ejemplo aún más concreto, que muestra cómo se puede subclasificar 'tipo' para hacer una metaclase que realiza una acción cuando se crea la clase. Esto es bastante complicado:
fuente
Otros han explicado cómo funcionan las metaclases y cómo encajan en el sistema de tipo Python. Aquí hay un ejemplo de para qué se pueden usar. En un marco de prueba que escribí, quería hacer un seguimiento del orden en que se definieron las clases, para poder luego instanciarlas en este orden. Me resultó más fácil hacer esto usando una metaclase.
Todo lo que sea una subclase
MyType
obtiene un atributo de clase_order
que registra el orden en que se definieron las clases.fuente
__init__(self)
dicetype(self)._order = MyBase.counter; MyBase.counter += 1
?Un uso para las metaclases es agregar nuevas propiedades y métodos a una instancia automáticamente.
Por ejemplo, si observa los modelos de Django , su definición parece un poco confusa. Parece que solo estás definiendo propiedades de clase:
Sin embargo, en tiempo de ejecución, los objetos Persona se llenan con todo tipo de métodos útiles. Vea la fuente de algunos metaclassery increíbles.
fuente
Creo que la introducción de ONLamp a la programación de metaclases está bien escrita y ofrece una muy buena introducción al tema a pesar de tener ya varios años.
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (archivado en https://web.archive.org/web/20080206005253/http://www.onlamp. com / pub / a / python / 2003/04/17 / metaclasses.html )
En resumen: una clase es un plan para la creación de una instancia, una metaclase es un plan para la creación de una clase. Se puede ver fácilmente que en Python las clases también deben ser objetos de primera clase para habilitar este comportamiento.
Nunca he escrito uno yo mismo, pero creo que uno de los mejores usos de las metaclases se puede ver en el marco de Django . Las clases de modelo utilizan un enfoque de metaclase para permitir un estilo declarativo de escribir nuevos modelos o clases de formulario. Mientras la metaclase está creando la clase, todos los miembros tienen la posibilidad de personalizar la clase en sí.
Lo que queda por decir es: si no sabe qué son las metaclases, la probabilidad de que no las necesite es del 99%.
fuente
TLDR: una metaclase crea instancias y define el comportamiento de una clase al igual que una clase crea instancias y define el comportamiento de una instancia.
Pseudocódigo:
Lo anterior debería parecer familiar. Bueno, de donde
Class
viene? Es una instancia de una metaclase (también pseudocódigo):En código real, podemos pasar la metaclase predeterminada
type
, todo lo que necesitamos para instanciar una clase y obtenemos una clase:Poniéndolo de manera diferente
Una clase es para una instancia como una metaclase para una clase.
Cuando instanciamos un objeto, obtenemos una instancia:
Del mismo modo, cuando definimos una clase explícitamente con la metaclase predeterminada
type
, la instanciamos:Dicho de otra manera, una clase es una instancia de una metaclase:
En tercer lugar, una metaclase es la clase de una clase.
Cuando escribe una definición de clase y Python la ejecuta, utiliza una metaclase para instanciar el objeto de clase (que, a su vez, se usará para instanciar instancias de esa clase).
Así como podemos usar definiciones de clase para cambiar cómo se comportan las instancias de objeto personalizadas, podemos usar una definición de clase de metaclase para cambiar la forma en que se comporta un objeto de clase.
¿Para qué se pueden usar? De los documentos :
Sin embargo, generalmente se recomienda a los usuarios evitar el uso de metaclases a menos que sea absolutamente necesario.
Utiliza una metaclase cada vez que crea una clase:
Cuando escribe una definición de clase, por ejemplo, así,
Instancias un objeto de clase.
Es lo mismo que llamar funcionalmente
type
con los argumentos apropiados y asignar el resultado a una variable con ese nombre:Tenga en cuenta que algunas cosas se agregan automáticamente
__dict__
al espacio de nombres, es decir:La metaclase del objeto que creamos, en ambos casos, es
type
.(Una nota al margen sobre el contenido de la clase
__dict__
:__module__
está ahí porque las clases deben saber dónde están definidas,__dict__
y__weakref__
están allí porque no definimos__slots__
; si definimos__slots__
ahorraremos un poco de espacio en las instancias, como podemos rechazar__dict__
y__weakref__
excluirlos, por ejemplo:... pero yo divago.)
Podemos extender
type
como cualquier otra definición de clase:Aquí está el valor predeterminado
__repr__
de las clases:Una de las cosas más valiosas que podemos hacer de forma predeterminada al escribir un objeto Python es proporcionarle un bien
__repr__
. Cuando llamamoshelp(repr)
, aprendemos que hay una buena prueba para una__repr__
que también requiere una prueba de igualdadobj == eval(repr(obj))
. La siguiente implementación simple de__repr__
y__eq__
para las instancias de clase de nuestra clase de tipo nos proporciona una demostración que puede mejorar el valor predeterminado__repr__
de las clases:Entonces, cuando creamos un objeto con esta metaclase, el
__repr__
eco en la línea de comando proporciona una vista mucho menos fea que la predeterminada:Con un buen
__repr__
definido para la instancia de clase, tenemos una mayor capacidad para depurar nuestro código. Sin embargo,eval(repr(Class))
es poco probable que se verifique mucho más (ya que las funciones serían bastante imposibles de evaluar desde sus valores predeterminados__repr__
).Un uso esperado:
__prepare__
un espacio de nombresSi, por ejemplo, queremos saber en qué orden se crean los métodos de una clase, podríamos proporcionar un dict ordenado como el espacio de nombres de la clase. Haríamos esto con lo
__prepare__
que devuelve el espacio de nombres dict para la clase si se implementa en Python 3 :Y uso:
Y ahora tenemos un registro del orden en que se crearon estos métodos (y otros atributos de clase):
Tenga en cuenta que este ejemplo fue adaptado de la documentación : la nueva enumeración en la biblioteca estándar hace esto.
Entonces, lo que hicimos fue crear una instancia de una metaclase creando una clase. También podemos tratar la metaclase como lo haríamos con cualquier otra clase. Tiene un orden de resolución de método:
Y tiene aproximadamente el correcto
repr
(que ya no podemos evaluar a menos que podamos encontrar una manera de representar nuestras funciones):fuente
Actualización de Python 3
Hay (en este punto) dos métodos clave en una metaclase:
__prepare__
y__new__
__prepare__
le permite proporcionar una asignación personalizada (como unaOrderedDict
) para usar como espacio de nombres mientras se crea la clase. Debe devolver una instancia del espacio de nombres que elija. Si no implementa__prepare__
un normaldict
se utiliza.__new__
es responsable de la creación / modificación real de la clase final.A una metaclase básica, sin hacer nada extra le gustaría:
Un simple ejemplo:
Supongamos que desea que se ejecute un código de validación simple en sus atributos, como si siempre fuera un
int
o unstr
. Sin una metaclase, su clase se vería así:Como puede ver, debe repetir el nombre del atributo dos veces. Esto hace posibles errores tipográficos junto con errores irritantes.
Una metaclase simple puede abordar ese problema:
Así es como se vería la metaclase (sin usar
__prepare__
ya que no es necesaria):Una muestra de ejecución de:
produce:
Nota : Este ejemplo es bastante simple, también podría haberse logrado con un decorador de clase, pero presumiblemente una metaclase real estaría haciendo mucho más.
La clase 'ValidateType' para referencia:
fuente
__set_name__(cls, name)
en el descriptor (ValidateType
) para establecer el nombre en el descriptor (self.name
y en este caso tambiénself.attr
). Esto se agregó para no tener que sumergirse en metaclases para este caso de uso común específico (ver PEP 487).Rol del
__call__()
método de una metaclase al crear una instancia de claseSi ha realizado la programación de Python durante más de unos meses, eventualmente tropezará con un código que se ve así:
Esto último es posible cuando implementa el
__call__()
método mágico en la clase.El
__call__()
método se invoca cuando una instancia de una clase se usa como invocable. Pero como hemos visto en las respuestas anteriores, una clase en sí misma es una instancia de una metaclase, por lo que cuando usamos la clase como invocable (es decir, cuando creamos una instancia de ella) en realidad estamos llamando al__call__()
método de su metaclase . En este punto, la mayoría de los programadores de Python están un poco confundidos porque se les ha dicho que al crear una instancia como estainstance = SomeClass()
, están llamando a su__init__()
método. Algunos que han profundizado un poco más lo saben antes de que__init__()
exista__new__()
. Bueno, hoy se revela otra capa de verdad, antes de que__new__()
haya una metaclase '__call__()
.Estudiemos la cadena de llamadas al método específicamente desde la perspectiva de crear una instancia de una clase.
Esta es una metaclase que registra exactamente el momento antes de crear una instancia y el momento en que está a punto de devolverla.
Esta es una clase que usa esa metaclase
Y ahora creemos una instancia de
Class_1
Observe que el código anterior en realidad no hace nada más que registrar las tareas. Cada método delega el trabajo real a la implementación de su padre, manteniendo así el comportamiento predeterminado. Dado que
type
esMeta_1
la clase principal (quetype
es la metaclase principal predeterminada) y considerando la secuencia de ordenación de la salida anterior, ahora tenemos una pista de cuál sería la pseudo implementación detype.__call__()
:Podemos ver que el
__call__()
método de la metaclase es el que se llama primero. Luego delega la creación de la instancia al__new__()
método de la clase y la inicialización a la instancia__init__()
. También es el que finalmente devuelve la instancia.De lo anterior se desprende que la metaclase
__call__()
también tiene la oportunidad de decidir si se hará o no una llamadaClass_1.__new__()
oClass_1.__init__()
, finalmente, se hará. En el transcurso de su ejecución, en realidad podría devolver un objeto que no ha sido tocado por ninguno de estos métodos. Tome por ejemplo este enfoque para el patrón singleton:Observemos lo que sucede cuando se intenta crear un objeto de tipo repetidamente
Class_2
fuente
Una metaclase es una clase que indica cómo (alguna) otra clase debería crearse.
Este es un caso en el que vi la metaclase como una solución a mi problema: tuve un problema realmente complicado, que probablemente podría haberse resuelto de manera diferente, pero decidí resolverlo usando una metaclase. Debido a la complejidad, es uno de los pocos módulos que he escrito donde los comentarios en el módulo superan la cantidad de código que se ha escrito. Aquí está...
fuente
La versión tl; dr
La
type(obj)
función te da el tipo de un objeto.El
type()
de una clase es su metaclase .Para usar una metaclase:
type
Es su propia metaclase. La clase de una clase es una metaclase: el cuerpo de una clase son los argumentos pasados a la metaclase que se utiliza para construir la clase.Aquí puede leer sobre cómo usar las metaclases para personalizar la construcción de clases.
fuente
type
en realidad esmetaclass
una clase que crea otras clases. La mayoríametaclass
son las subclases detype
. Lametaclass
recibe lanew
clase como su primer argumento y proporcionan acceso a objeto de clase con detalles como se menciona a continuación:Note:
Note que la clase no fue instanciada en ningún momento; El simple acto de crear la clase desencadenó la ejecución de
metaclass
.fuente
Las clases de Python son en sí mismas objetos, como por ejemplo, de su metaclase.
La metaclase predeterminada, que se aplica cuando determina clases como:
Las metaclases se utilizan para aplicar alguna regla a un conjunto completo de clases. Por ejemplo, suponga que está creando un ORM para acceder a una base de datos y desea que los registros de cada tabla sean de una clase asignada a esa tabla (basada en campos, reglas comerciales, etc.), un posible uso de metaclase es, por ejemplo, la lógica del grupo de conexiones, que comparten todas las clases de registros de todas las tablas. Otro uso es la lógica para soportar claves foráneas, que involucra múltiples clases de registros.
cuando define metaclase, subclase tipo, y puede anular los siguientes métodos mágicos para insertar su lógica.
de todos modos, esos dos son los ganchos más utilizados. la metaclase es poderosa, y arriba no hay ninguna lista exhaustiva de usos para la metaclase.
fuente
La función type () puede devolver el tipo de un objeto o crear un nuevo tipo,
por ejemplo, podemos crear una clase Hi con la función type () y no es necesario usarla de esta manera con la clase Hi (objeto):
Además de usar type () para crear clases dinámicamente, puede controlar el comportamiento de creación de la clase y usar metaclase.
Según el modelo de objetos de Python, la clase es el objeto, por lo que la clase debe ser una instancia de otra clase determinada. Por defecto, una clase de Python es una instancia de la clase de tipo. Es decir, tipo es metaclase de la mayoría de las clases integradas y metaclase de clases definidas por el usuario.
La magia tendrá efecto cuando pasamos argumentos de palabras clave en metaclase, indica que el intérprete de Python creará la Lista personalizada a través de ListMetaclass. new (), en este punto, podemos modificar la definición de clase, por ejemplo, y agregar un nuevo método y luego devolver la definición revisada.
fuente
Además de las respuestas publicadas, puedo decir que a
metaclass
define el comportamiento de una clase. Por lo tanto, puede establecer explícitamente su metaclase. Cada vez que Python obtiene una palabra claveclass
, comienza a buscarlametaclass
. Si no se encuentra, el tipo de metaclase predeterminado se usa para crear el objeto de la clase. Usando el__metaclass__
atributo, puede establecermetaclass
su clase:Producirá la salida de esta manera:
Y, por supuesto, puedes crear tu propio
metaclass
para definir el comportamiento de cualquier clase que se cree utilizando su clase.Para hacerlo, su
metaclass
clase de tipo predeterminada debe heredarse ya que esta es la principalmetaclass
:El resultado será:
fuente
En la programación orientada a objetos, una metaclase es una clase cuyas instancias son clases. Así como una clase ordinaria define el comportamiento de ciertos objetos, una metaclase define el comportamiento de cierta clase y sus instancias. El término metaclase simplemente significa algo utilizado para crear clases. En otras palabras, es la clase de una clase. La metaclase se usa para crear la clase, de modo que, como el objeto es una instancia de una clase, una clase es una instancia de una metaclase. En python las clases también se consideran objetos.
fuente
Aquí hay otro ejemplo de para qué se puede usar:
metaclass
para cambiar la función de su instancia (la clase).El
metaclass
es poderoso, hay muchas cosas (como la magia de los monos) que puedes hacer con él, pero ten cuidado de que esto solo lo sepas tú.fuente
Una clase, en Python, es un objeto, y al igual que cualquier otro objeto, es una instancia de "algo". Este "algo" es lo que se denomina Metaclase. Esta metaclase es un tipo especial de clase que crea los objetos de otra clase. Por lo tanto, metaclass es responsable de hacer nuevas clases. Esto permite al programador personalizar la forma en que se generan las clases.
Para crear una metaclase, generalmente se reemplaza los métodos new () e init (). new () se puede reemplazar para cambiar la forma en que se crean los objetos, mientras que init () se puede reemplazar para cambiar la forma de inicializar el objeto. Metaclass se puede crear de varias maneras. Una de las formas es usar la función type (). La función type (), cuando se llama con 3 parámetros, crea una metaclase. Los parámetros son: -
Otra forma de crear una metaclase consiste en la palabra clave 'metaclase'. Defina la metaclase como una clase simple. En los parámetros de la clase heredada, pase metaclass = metaclass_name
Metaclass se puede usar específicamente en las siguientes situaciones: -
fuente
Tenga en cuenta que en Python 3.6
__init_subclass__(cls, **kwargs)
se introdujo un nuevo método dunder para reemplazar muchos casos de uso comunes para metaclases. Se llama cuando se crea una subclase de la clase definitoria. Ver documentos de Python .fuente
Metaclass es un tipo de clase que define cómo se comportará la clase o podemos decir que una clase es en sí misma una instancia de una metaclase.
fuente