Pregunta

He leído algunos tutoriales sobre metaclases Python. Nunca he usado uno antes, pero necesito uno para algo relativamente simple y todos los tutoriales parecen orienta hacia los casos de uso mucho más complejas. Básicamente quiero crear una clase de plantilla que tiene un cuerpo pre-especificado, pero toma su clase base como parámetro. Desde que ocurrió la idea a partir de plantillas de C ++ / D, he aquí un ejemplo de lo que el código que desea escribir se vería como en C ++:

template<class T>
    class Foo : T {
        void fun() {}
    }
¿Fue útil?

Solución

A pesar de que sin duda se puede hacer con metaclases, puede hacer lo que quiera sin ellos porque en las clases de Python son objetos mismos. Los medios que, sorprendentemente, esencialmente nada más que una traducción casi uno-a-uno de código de C ++ es necesario. Además de ser relativamente poco complicado debido a esto, sino que también va a trabajar sin modificaciones tanto en Python 2 y 3.

def template(class_T):
    """Factory function to create subclasses of class_T."""

    class Foo(class_T):
        def fun(self):
            print('%s.fun()' % self.__class__.__name__)

    Foo.__name__ += '_' + class_T.__name__  # rename the subclass to reflect its heritage
    return Foo

class Base1:
    def bar(self):
        print('Base1.bar()')

class Base2:
    def bar(self):
        print('Base2.bar()')

Foo_Base1 = template(Base1)
print('Foo_Base1 base classes: {}'.format(Foo_Base1.__bases__))

Foo_Base2 = template(Base2)
print('Foo_Base2 base classes: {}'.format(Foo_Base2.__bases__))

subclass1 = Foo_Base1()
subclass1.fun()
subclass1.bar()
subclass2 = Foo_Base2()
subclass2.fun()
subclass2.bar()

Salida:

Foo_Base1 base classes: (<class __main__.Base1 at 0x00A79C38>,)
Foo_Base2 base classes: (<class __main__.Base2 at 0x00A79DC0>,)
Foo_Base1.fun()
Base1.bar()
Foo_Base2.fun()
Base2.bar()

El código de la función template() (unimaginatively-nombrado) es un ejemplo de lo que se llama comúnmente una fábrica de clase o una implementación de la patrón de fábrica . Por lo tanto, dicho sea de paso, es posible encontrar mi respuesta a la pregunta ¿Qué es exactamente un generador de clases? informativo.

Editar Añadido código para crear diferentes nombres de clase para cada subclase regresó-que fue inspirado por @ aaronasterling 's visión (en un comentario ahora suprimido) sobre una posible confusión en la depuración de si la clase fabricada siempre tiene el mismo nombre.

Otros consejos

Esto no tiene sentido en Python, ya que no tiene plantillas. Mi comprensión de las plantillas parametrizado en C ++ (que es bastante impreciso, ya que es muchos años desde que he mirado), es que actúa como un generador de clases, y puede crear una subclase de cualquier clase que darle que tiene métodos adicionales o atributos añadidos.

En Python se puede hacer esto con una función fábrica que toma una clase y devuelve una nueva clase en tiempo de ejecución:

In [1]: def subclassFactory(cls):
   ...:     class Foo(cls):
   ...:         def fun(self):
   ...:             return "this is fun"
   ...:     return Foo
   ...: 

In [2]: class A(object):
   ...:     pass
   ...: 

In [5]: C = subclassFactory(A)

In [6]: C
Out[6]: <class '__main__.Foo'>
In [7]: c = C()
In [9]: c.fun()
Out[9]: 'this is fun'
In [10]: isinstance(c, A)
Out[10]: True
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top