Segundo parámetro de super ()?

Un colega mío escribió un código análogo al siguiente de hoy, me pidió que echara un vistazo y me llevó un tiempo descubrir el error:

class A(): def __init__(self): print('A') class B(A): def __init__(self): super(B).__init__() b = B() 

El problema aquí es que no hay ningún parámetro para super() en el constructor de B Lo que me sorprendió es que no pasa absolutamente nada en este caso, es decir, no hay error, nada. ¿Qué contiene el super objeto creado por super(B) ? Como objeto, claramente tiene un constructor, así que eso es lo que se llama, pero ¿cómo se relaciona ese objeto con B ? En particular, ¿por qué es este código válido y no lanza una excepción en algún lugar? ¿Es super(B) un objeto con algún uso real y cuál sería?

Lo único que causa todas estas ambigüedades es que “¿por qué obj = super(B).__init__() funciona?”. Esto se debe a que super(B).__self_class__ devuelve None y, en ese caso, está llamando a los objetos None __init__ como a continuación, que devuelve Ninguno:

 In [40]: None.__init__() 

Con respecto al rest de los casos, simplemente puede verificar la diferencia llamando a los atributos esenciales del super en ambos casos:

 In [36]: class B(A): def __init__(self): obj = super(B, self) print(obj.__class__) print(obj.__thisclass__) print(obj.__self_class__) print(obj.__self__) ....: In [37]: b = B()    <__main__.B object at 0x7f15a813f940> In [38]: In [38]: class B(A): def __init__(self): obj = super(B) print(obj.__class__) print(obj.__thisclass__) print(obj.__self_class__) print(obj.__self__) ....: In [39]: b = B()   None None 

Para el rest de las cosas le recomiendo que lea la documentación a fondo. https://docs.python.org/3/library/functions.html#super y este artículo de Raymond Hettinger https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ .

Además, si desea saber por qué super(B) no funciona fuera de la clase y, en general, por qué llamar a super() sin ningún argumento funciona dentro de una clase, puede leer Esta respuesta integral de Martijn https://stackoverflow.com / a / 19609168/2867928 .

Una breve descripción de la solución:

Como se menciona en los comentarios de @Nathan Vērzemnieks, debe llamar al inicializador una vez para que funcione el objeto super() . El motivo se encuentra detrás de la magia del nuevo super objeto que se explica en los enlaces mencionados anteriormente.

 In [1]: class A: ...: def __init__(self): ...: print("finally!") ...: In [2]: class B(A): ...: def __init__(self): ...: sup = super(B) ...: print("Before: {}".format(sup)) ...: sup.__init__() ...: print("After: {}".format(sup)) ...: sup.__init__() ...: In [3]: B() Before: , NULL> After: , > finally! 

La confusión aquí proviene del hecho de que (en un contexto de definición de clase) super() proporciona un objeto super enlazado que luego delega __init__ a su __self_class__ , mientras que super(B) crea un objeto super no __self_class__ que, debido a que __self_class__ es None , no delegar

 In [41]: class Test(int): ...: def __init__(self): ...: print(super().__self_class__) ...: print(super().__init__) ...: print(super(Test).__self_class__) ...: print(super(Test).__init__) ...: In [42]: Test()   None  

Por lo tanto, cuando llama a super(B).__init__() , crea un super __init__ pero inmediatamente llama a __init__ en él; eso, debido a la magia descrita en los diversos enlaces en esta otra respuesta , se une a ese super sin super . No hay referencias a él, por lo que desaparece, pero eso es lo que está sucediendo bajo el capó.