2012-05-20 4 views

Respuesta

12

No estoy seguro de a qué limitaciones se refería el autor del tutorial de python, pero supongo que tiene que ver en parte con la forma en que se implementa la búsqueda de método/atributo en python (el "orden de resolución de método" o MRO). Python usa el mecanismo C3 superclass linearization; esto es para tratar con lo que se llama ser "The Diamond Problem".

Una vez que haya introducido la herencia múltiple en su jerarquía de clases, cualquier clase dada no tiene una única clase potencial de la que hereda, solo tiene "la siguiente clase en el MRO", incluso para las clases que esperan que ellos heredan de alguna clase en particular.

Por ejemplo, si class A(object), class B(A), class C(A), y class D(B, C), entonces el MRO para la clase D es D->B->C->A. La clase B podría haberse escrito, probablemente, pensando que desciende de A, y cuando llama al super() en sí mismo, obtendrá un método en A. Pero esto ya no es cierto; cuando B llama al super(), obtendrá un método en C, si existe.

Si cambia las firmas de método en métodos anulados esto puede ser un problema. La clase B, que espera la firma de un método de la clase A cuando llama a súper, obtiene un método de C, que podría no tener esa firma (y podría o no implementar el comportamiento deseado, desde el punto de vista de la clase B).

class A(object): 
    def __init__(self, foo): 
     print "A!" 

class B(A): 
    def __init__(self, foo, bar): 
     print "B!" 
     super(B, self).__init__(foo) 

class C(A): 
    def __init__(self, foo, baaz): 
     print "C!" 
     super(C, self).__init__(foo) 

class D(B, C): 
    def __init__(self, foo, bar): 
     print "D!" 
     super(D, self).__init__(foo, bar) 

print D.mro() 
D("foo", "bar") 

En este ejemplo de código, las clases B y C han ampliado razonablemente A, y ha cambiado sus __init__ firmas, pero llame a su firma superclase espera correctamente. Pero cuando haces D así, la efectiva "superclase" de B se convierte en C en lugar de A. Cuando se llama a super, las cosas explotan:

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>] 
D! 
B! 
Traceback (most recent call last): 
    File "/tmp/multi_inherit.py", line 22, in <module> 
    D("foo", "bar") 
    File "/tmp/multi_inherit.py", line 19, in __init__ 
    super(D, self).__init__(foo, bar) 
    File "/tmp/multi_inherit.py", line 9, in __init__ 
    super(B, self).__init__(foo) 
TypeError: __init__() takes exactly 3 arguments (2 given) 

Este mismo tipo de cosas podría ocurrir por otros métodos también (si llaman al super()), y el "diamante" no tiene que aparecer solo en la raíz de la jerarquía de clases.

+7

Todo esto es cierto, pero cualquier lenguaje con herencia múltiple tiene que lidiar con estos problemas. Si suponemos que su respuesta es correcta, ¿qué idioma (con MI) * no * tendría una forma limitada de herencia múltiple? –