¿Puede Super tratar con herencia múltiple?

Al heredar de dos objetos como estos.

class Foo(object): def __init__(self,a): self.a=a class Bar(object): def __init__(self,b): self.b=b 

Normalmente haria algo como esto

 class FooBar(Foo,Bar): def __init__(self,a,b): Foo.__init__(self,a) Bar.__init__(self,b) 

¿Cómo sabe super si quiero llamar a los dos? y si es así, ¿cómo sabrá qué argumento pasar dónde? ¿O simplemente no es posible el usuario super aquí?

Incluso si Foo y Bar toman los mismos argumentos, ¿pueden lidiar con esto?

¿O no debería estar tratando de hacer este tipo de esto en primer lugar?

Usar super() , __init__() y herencia múltiple es un poco complicado.

En el flujo normal de cosas, todos los métodos se llaman super() , con las clases que heredan solo del object haciendo un poco de trabajo extra para asegurarse de que el método realmente existe: se verá un poco así:

 >>> class Foo(object): ... def frob(self, arg): ... print "Foo.frob" ... if hasattr(super(Foo, self), 'frob'): ... super(Foo, self).frob(arg) ... >>> class Bar(object): ... def frob(self, arg): ... print "Bar.frob" ... if hasattr(super(Bar, self), 'frob'): ... super(Bar, self).frob(arg) ... >>> class Baz(Foo, Bar): ... def frob(self, arg): ... print "Baz.frob" ... super(Baz, self).frob(arg) ... >>> b = Baz() >>> b.frob(1) Baz.frob Foo.frob Bar.frob >>> 

Pero cuando intentas hacer algo similar con un método que realmente tiene el object , las cosas se ponen un poco arriesgadas; object.__init__ no acepta argumentos, por lo que la única forma segura de usarlo es llamar a super().__init__() sin argumentos, ya que esa llamada puede ser manejada por el object.__init__ . Pero entonces podría no ser manejado por el object.__init__ , y en su lugar manejado por una clase en otra parte en el gráfico de herencia. Por lo tanto, cualquier clase que defina __init__ en una jerarquía de clase de herencia múltiple debe estar preparada para ser llamada sin argumentos .

una forma de lidiar con esto es nunca usar argumentos en __init__() . Realice una inicialización mínima y confíe en establecer propiedades o utilizar otros medios para configurar el nuevo objeto antes de usarlo. Eso es bastante desagradable, sin embargo.

Otra forma es usar solo argumentos de palabras clave, algo como def __init__(self, **keywords): y siempre eliminar los argumentos que se aplican al constructor dado. Esta es una estrategia basada en la esperanza, usted espera que todas las palabras clave se consumn antes de que el control scope el object.__init__ .

Una tercera forma es definir una superclase para todas las bases de herencia múltiple que, a su vez, define a __init__ de alguna manera útil y no llama a super().__init__ (el object.__init__ es una object.__init__ ). Esto significa que puede estar seguro de que este método siempre se llama último, y puede hacer lo que quiera con sus argumentos.

¿O no debería estar tratando de hacer este tipo de esto en primer lugar?

Correcto. Debería estar llamando solo a una línea padre de __init__ s, no a un árbol. super utilizará el MRO para realizar una búsqueda en profundidad de las clases para padres buscando el __init__ apropiado para llamar. No llamará ni debe llamar a todos los __init__ s posibles.