2010-07-27 24 views
9

Tengo una pregunta esotérica que involucra metaclases de Python. Estoy creando un paquete de Python para el código del lado del servidor web que facilitará el acceso a clases arbitrarias de Python a través de proxies del lado del cliente. Mi código generador de proxy necesita un catálogo de todas las clases de Python que quiero incluir en mi API. Para crear este catálogo, estoy usando el atributo especial __metaclass__ para poner un gancho en el proceso de creación de clase. Específicamente, todas las clases en la API "publicada" subclasificarán una clase base particular, PythonDirectPublic, que a su vez tiene un __metaclass__ que se ha configurado para registrar información sobre la creación de clases.Python: Metaclasses hasta el final

Hasta ahora todo bien. Donde se complica es que quiero que mi PythonDirectPublic herede de una clase de terceros (enthought.traits.api.HasTraits). Esta clase de terceros también usa un __metaclass__.

Entonces, ¿cuál es la forma correcta de administrar dos metaclases? ¿Debería mi metaclase ser una subclase de la metaclase de Enthought? ¿O debería invocar la metaclase de Enthought dentro del método __new__ de mi metaclase para obtener el tipo de objeto que devolveré? ¿O hay algún otro encantamiento místico para usar en esta circunstancia particular?

Respuesta

5

¿Debería mi metaclase ser una subclase de la metaclase de Enthought?

Creo que de hecho es su única opción. Si la metaclase de una clase derivada no es una subclase de las metaclases de todas sus bases, entonces Python lanzará un TypeError cuando intente crear la clase derivada. Por lo que su metaclase para PythonDirectPublic debería ser algo como

class DerivedMetaClass(BaseMetaClass): 
    def __new__(cls, name, bases, dct): 
     # Do your custom memory allocation here, if any 

     # Now let base metaclass do its memory allocation stuff 
     return BaseMetaClass.__new__(cls, name, bases, dct) 

    def __init__(cls, name, bases, dct): 
     # Do your custom initialization here, if any 
     # This, I assume, is where your catalog creation stuff takes place 

     # Now let base metaclass do its initialization stuff 
     super(DerivedMetaClass, cls).__init__(name, bases, dct) 

Si usted no tiene acceso a la definición de la metaclase para su clase base de terceros, puede reemplazar BaseMetaClass con enthought.traits.api.HasTraits.__metaclass__. Es prolijo, pero funcionará.

1

En concreto, todas las clases de la API "publicada" se subclase de una clase base concreta, PythonDirectPublic

En lugar de añadir otra metaclase, se puede usar de forma recursiva el resultado de PythonDirectPublic. subclases().

+0

No encuentro ninguna documentación sobre ese método en particular. ¿Sugiere usar HasTraits.trait_subclasses()? Eso podría haber proporcionado un enfoque alternativo para construir el catálogo. –

+0

@DanMenes Creo que Dan Ellis realmente se refiere al método '__subclasses__', ver [esta respuesta] (http://stackoverflow.com/a/3862957/396967) para saber cómo usarlo. – kynan

+0

@kynan Lo tengo. Creo que eso también funcionaría. Aunque han pasado un par de años desde que miré este código, así que no recuerdo todas las arrugas –

Cuestiones relacionadas