Al llamar a super () en una clase derivada, ¿puedo pasar auto .__ class__?

Recientemente descubrí (a través de StackOverflow) que para llamar a un método en una clase base debería llamar:

super([[derived class]], self).[[base class method]]()

Eso está bien, funciona. Sin embargo, a menudo me encuentro copiando y pegando entre clases cuando hago un cambio y con frecuencia me olvido de arreglar el argumento de clase derivado a la función super ().

Me gustaría evitar tener que recordar cambiar el argumento de clase derivado. ¿Puedo en cambio simplemente usar self.__class__ como el primer argumento de la función super ()?

Parece funcionar pero ¿hay buenas razones por las que no debería hacer esto?

No, no puedes. La llamada super() necesita saber de qué clase forma parte el método, para buscar en las clases base un método anulado.

Si pasas en self.__class__ (o mejor aún, type(self) ), a super() se le da un punto de inicio incorrecto para buscar métodos y terminará llamando a su propio método nuevamente .

Véalo como un puntero en la lista de clases que forman la secuencia Orden de resolución de métodos. Si pasa el type(self) , el puntero se referirá a cualquier subclase en lugar del punto de inicio original.

El siguiente código lleva a un error de recursión infinito:

 class Base(object): def method(self): print 'original' class Derived(Base): def method(self): print 'derived' super(type(self), self).method() class Subclass(Derived): def method(self): print 'subclass of derived' super(Subclass, self).method() 

Manifestación:

 >>> Subclass().method() subclass of derived derived derived derived <... *many* lines removed ...> File "", line 4, in method File "", line 4, in method File "", line 4, in method RuntimeError: maximum recursion depth exceeded while calling a Python object 

porque type(self) es Subclass , no Derived , en Derived.method() .

En el ejemplo, el MRO para Subclass es [Subclass, Derived, Base] , y super() necesita saber dónde comenzar a buscar cualquier método anulado. Al usar type(self) le dices que comience en Subclass , por lo que encontrará Derived.method() continuación, que es donde empezamos.

self.__class__ podría no ser una subclase, sino una clase de nieto o menor, lo que lleva a un bucle que rompe la stack.