2009-05-05 25 views
14

Por lo tanto, creo que el código probablemente explica por qué estoy tratando de hacerlo mejor que puedo con palabras, así que aquí va:clase abstracta + + mixin herencia múltiple en Python

import abc 

class foo(object): 
    __metaclass__ = abc.ABCMeta 
    @abc.abstractmethod 
    def bar(self): 
     pass 


class bar_for_foo_mixin(object): 
    def bar(self): 
     print "This should satisfy the abstract method requirement" 


class myfoo(foo, bar_for_foo_mixin): 
    def __init__(self): 
     print "myfoo __init__ called" 
     self.bar() 

obj = myfoo() 

El resultado:

TypeError: Can't instantiate abstract class myfoo with abstract methods bar 

estoy tratando de conseguir la clase mixin para satisfacer los requisitos de la clase abstracta/interfaz. ¿Qué me estoy perdiendo?

Respuesta

15

¿No debería ser la herencia al revés? En el MRO foo actualmente viene antes de bar_for_foo_mixin, y luego se queja con razón. Con class myfoo(bar_for_foo_mixin, foo) debería funcionar.

Y no estoy seguro de si el diseño de su clase es la forma correcta de hacerlo. Como utiliza un mixin para implementar bar, es mejor no derivar de foo y simplemente registrarlo con la clase 'foo' (es decir, foo.register(myfoo)). Pero esto es solo mi instinto.

Para completar, aquí es el documentation for ABCs.

+0

Buena decisión, cambiando el orden de herencia hace el truco . P.S. el código fue simplificado para ilustrar un punto. Mi escenario del mundo real es mucho más complejo con muchos mixins potenciales y muchos myfoos. – mluebke

0

Creo que (a prueba en caso similar) que revertir los baseclasses funciona:

class myfoo(bar_for_foo_mixin, foo): 
    def __init__(self): 
     print "myfoo __init__ called" 
     self.bar() 

por lo que en el MRO() sería encontrar una versión concreta de la barra() antes de que encuentre el abstracto. Sin embargo, ni idea de si esto es realmente lo que sucede en el fondo.

Cheers, Lars

PD: el código que trabajó en Python 2.7 (Python 3 tiene una forma diferente para establecer metaclases) fue:

class A(object): 
    __metaclass__ = abc.ABCMeta 

    @abc.abstractmethod 
    def do(self): 
     pass 

class B(object): 
    def do(self): 
     print "do" 

class C(B, A): 
    pass 

c = C() 
+0

Gracias por esta respuesta. En py27, el código que funcionó efectivamente impone la presencia de 'do()' en la clase 'C'. Sin embargo, en py3 (solo probé en py35), este ya no es el caso. En la clase 'B' puedes reemplazar el cuerpo con' pass', y la instancia 'c' será felizmente creada. ¿Sabes por qué esto podría ser? –

+0

@cjrh: ¿te refieres al cuerpo de B o al cuerpo de B.do? Si es el primero, sería realmente extraño porque desafiaría el propósito de abc .. – Lars

+0

Simplemente pruebe su código en "PS: el código que funcionó", pero cambie 'B' por' clase B (objeto): pasar'. Verás que la instancia 'c' se creó con éxito. Intenté con Python 3.6, el mismo resultado. –