2010-01-05 28 views
30

¿Qué se puede hacer con las metaclases que no pueden ser de otra manera?¿Para qué sirven las metaclases de Python?

Alex Martelli dijo que hay tareas que no se pueden lograr sin metaclases aquí Python metaclasses vs class decorators Me gustaría saber cuáles son?

+7

Recuerdo que leí en un lugar como este sobre las metaclases, citado de manera muy vaga: "si tiene que preguntar para qué sirven, significa que no las va a necesitar". +1, pregunta interesante. –

+3

No estoy seguro de que "no se pueda hacer de otra manera" es un criterio útil. Casi todo se puede hacer de muchas maneras diferentes, todo es cuestión de lo fácil/natural que es. –

+0

Debería haber una, y preferiblemente solo una, forma obvia de hacerlo. :) –

Respuesta

18

metaclases son indispensables si se quiere tener objetos de clase (en contraposición a casos de objetos de clase) equipadas con un "comportamiento personalizado especial", ya que el comportamiento de un objeto depende de métodos especiales en el tipo del objeto, y el tipo de objeto de clase es, exactamente un sinónimo de, la metaclase.

Por ejemplo, si quiere un objeto de clase X tal que "imprimir X" emite "El tiempo es ahora 8:46 a.m." (a las 8:46 a.m., más generalmente, la hora actual) debe significar que type(x) (Metaclass AKA X) tiene un método especial personalizado __str__ - y de manera similar (con los diversos métodos especiales aplicables) si desea dar significado a expresiones como X + Y donde X e Y son ambos objetos de clase, o X[23] (donde X, de nuevo, es un objeto de clase), y así sucesivamente.

La mayoría de las otras tareas de personalización son ahora (en Python 2.6 o mejor) más fáciles de implementar con un decorador de clases, que puede alterar un objeto de clase justo después del final de la instrucción class. Hay algunos casos más en los que esto no es factible porque las modificaciones se deben realizar desde el principio para que tengan algún efecto (por ejemplo, configurar o modificar __slots__).

En Python 3, metaclases ganan un poco más de utilidad: una metaclase ahora puede especificar opcionalmente el objeto de asignación a poblarse durante la ejecución del cuerpo de la declaración class (por defecto, que es una normal de dict). Esto permite ordenar de enlaces de nombre en el cuerpo de la clase para preservar y usar (mientras que el dict normal pierde el orden), que a veces es agradable cuando la clase debe tener "campos" en un orden específico específico (por ejemplo, al mapa 1: 1 en un C struct, una fila en un archivo CSV o tabla DB, y similares) - en Python 2. * esto tenía que ser especificado de forma redundante (generalmente con un atributo de clase adicional que es una secuencia y así se conserva el orden), y esta característica de las metaclases de Python 3 permite eliminar la redundancia.

10

añaden flexibilidad a su programación:

Pero de acuerdo con esta Metaclass programming in Python es posible que no los necesita (todavía)

metaclases son más profundas mágica del 99% de los usuarios nunca debe preocuparse. Si se pregunta si los necesita, no (las personas que realmente los necesitan saben con certeza que los necesitan y no necesitan una explicación sobre por qué).

- Python Guru Tim Peters

+15

Todavía quiero saber. –

+0

Piense en la programación orientada a aspectos. El enlace que publiqué contiene una explicación completa y ejemplos de código. – OscarRyz

+0

Lo leí antes de publicar la pregunta y tengo solo 1 ejemplo. –

1

Rara vez se necesitan, pero resultar muy útil en lugares en los que desea añadir el comportamiento al comportamiento básico de un objeto - comparar programación orientada a aspectos, o la instrumentación hecha en marcos de persistencia como Hibernate.

Por ejemplo, es posible que desee una clase que persista o registre cada objeto nuevo.

+2

¿No se puede hacer esto con decoradores? –

4

Si está buscando ejemplos del uso del mecanismo de metaclase, puede leer el código fuente django.forms.

El estilo declarativo de la definición de formulario se implementa mediante metaclass.

1

Probablemente no se puede hacer nada exclusivamente con metaclases, pero para algunas personas (la mía incluida) es una herramienta interesante que puede usar. Solo tenga cuidado de no abusar, ya que puede ser complicado.

Por ejemplo, he utilizado la metaprogramación en un proyecto reciente. Era una hoja de cálculo de OpenOffice que, al usar algunas macros de pyUNO, genera algunos archivos con información. Había una hoja que presenta al usuario la información que debe rellenar, y las otras se pueden utilizar para describir el tipo de elementos y sus propiedades. El usuario puede seleccionar la cantidad de elementos y el tipo de cada uno y generar los archivos. La macro creará una clase mediante metaprogramación siguiendo la configuración de cada hoja. Luego, el usuario puede instanciar cada clase y generar objetos.

Se podía hacer sin metaprogramación, pero a mí me parecía natural usar las capacidades de metaprogramación para hacerlo.

1

Eche un vistazo a las fuentes de Django; por ejemplo, las metaclases se usan allí para generar modelos.

http://code.djangoproject.com/wiki/DynamicModels

Internamente, Django usa metaclases a modelos basados ​​en crear una clase que proporcione en su código fuente. Sin entrar en demasiados detalles, que significa que en lugar de sus clases siendo los modelos reales, Django recibe una descripción de su clase, que utiliza para crear un modelo en su lugar .

8

Uso las metaclases con cierta frecuencia, y son una herramienta extremadamente poderosa para tener en la caja de herramientas. A veces, su solución a un problema puede ser más elegante, con menos código, con ellos que sin ellos.

Lo que me resulta más frecuente al usar metaclases es el postprocesamiento de los atributos de clase durante la creación de la clase. Por ejemplo, establecer un atributo name en los objetos en su caso (como la forma de la ORM de Django podría funcionar):

class AutonamingType(type): 
    def __init__(cls, name, bases, attrs): 
     for k,v in attrs.iteritems(): 
      if getattr(v, '__autoname__', False): 
       v.name = k 

class Autonamer(object): 
    __metaclass__ = AutonamingType 

Si usted tiene esto como una herramienta, y está usando una clase que debe conocer su name antes de que se puede do_something():

class Foo(object): 
    __autoname__ = True 
    def __init__(self, name=None): 
     self.name = name 
    def do_something(self): 
     if self.name is None: 
      raise ValueError('name is None') 
     # now, do something 

Se puede hacer la diferencia en el resto de su código entre este:

class Bar(object): 
    myfoo1 = Foo('myfoo1') 
    myfoo2 = Foo('myfoo2') 
    myfoo3 = Foo('myfoo3') 

y esto:

class Baaz(Autonamer): 
    myfoo1 = Foo() 
    myfoo2 = Foo() 
    myfoo3 = Foo() 

reduciendo así la duplicación (y las posibilidades de que el nombre de la variable y el nombre asignado se salgan de sincronización).

0

El primer comentarista afirma que el uso de las metaclases here fue 'una piedra preciosa' que lo ayudó a localizar errores inesperados que habían estado ocurriendo durante (muchos) 'días'.

Cuestiones relacionadas