Estoy tratando de aprender la función super () en Python.
Pensé que lo entendía hasta que encontré este ejemplo (2.6) y me encontré atascado.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.py", line 9, in do_something
do_something = classmethod(do_something)
TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)
>>>
No era lo que esperaba cuando leí esta línea justo antes del ejemplo:
Si estamos usando un método de clase, no tenemos una instancia para llamar a super. Afortunadamente para nosotros, super funciona incluso con un tipo como segundo argumento. --- El tipo se puede pasar directamente a super como se muestra a continuación.
Que es exactamente lo que Python me dice que no es posible al decir que do_something () debería llamarse con una instancia de B.

Respuestas:
A veces, los textos deben leerse más por el sabor de la idea que por los detalles. Este es uno de esos casos.
En la página enlazada , los Ejemplos 2.5, 2.6 y 2.7 deben todo el método de un solo uso,
do_your_stuff. (Es decir,do_somethingdebería cambiarse ado_your_stuff.)Además, como señaló Ned Deily ,
A.do_your_stufftiene que ser un método de clase.class A(object): @classmethod def do_your_stuff(cls): print 'This is A' class B(A): @classmethod def do_your_stuff(cls): super(B, cls).do_your_stuff() B.do_your_stuff()super(B, cls).do_your_stuffdevuelve un método enlazado (ver nota al pie 2 ). Dado queclsse pasó como segundo argumento asuper(), es elclsque se vincula al método devuelto. En otras palabras,clsse pasa como primer argumento al métododo_your_stuff()de la clase A.Para reiterar:
super(B, cls).do_your_stuff()causasA'sdo_your_stuffmétodo para ser llamados conclspasado como primer argumento. Para que eso funcione,A'sdo_your_stufftiene que haber un método de clase. La página vinculada no menciona eso, pero ese es definitivamente el caso.PD.
do_something = classmethod(do_something)es la forma antigua de hacer un método de clase. La nueva (más) forma es usar el decorador @classmethod.Tenga en cuenta que
super(B, cls)no puede ser reemplazado porsuper(cls, cls). Hacerlo podría dar lugar a bucles infinitos. Por ejemplo,class A(object): @classmethod def do_your_stuff(cls): print('This is A') class B(A): @classmethod def do_your_stuff(cls): print('This is B') # super(B, cls).do_your_stuff() # CORRECT super(cls, cls).do_your_stuff() # WRONG class C(B): @classmethod def do_your_stuff(cls): print('This is C') # super(C, cls).do_your_stuff() # CORRECT super(cls, cls).do_your_stuff() # WRONG C.do_your_stuff()levantará
RuntimeError: maximum recursion depth exceeded while calling a Python object.Si
clses asíC,super(cls, cls)buscaC.mro()la clase que viene despuésC.In [161]: C.mro() Out[161]: [__main__.C, __main__.B, __main__.A, object]Dado que esa clase es
B, cuandoclsesC,super(cls, cls).do_your_stuff()siempre llamaB.do_your_stuff. Comosuper(cls, cls).do_your_stuff()se llama por dentroB.do_your_stuff, terminas llamandoB.do_your_stuffen un bucle infinito.En Python3, se agregó la forma de argumento 0 de, por
superlo quesuper(B, cls)podría reemplazarse porsuper(), y Python3 averiguará a partir del contexto quesuper()en la definición declass Bdebería ser equivalente asuper(B, cls).Pero en ninguna circunstancia
super(cls, cls)(o por razones similaressuper(type(self), self)) nunca es correcto.fuente
super(cls, cls)es casi seguro un error. Edité la publicación anterior para explicar por qué.En Python 3, puede omitir la especificación de argumentos para
super,class A: @classmethod def f(cls): return "A's f was called." class B(A): @classmethod def f(cls): return super().f() assert B.f() == "A's f was called."fuente
RuntimeError: super(): no argumentsActualicé el artículo para que quede un poco más claro: Atributos y métodos de Python # Super
Su ejemplo de uso de método de clase anterior muestra qué es un método de clase: pasa la clase misma en lugar de la instancia como primer parámetro. Pero ni siquiera necesita una instancia para llamar al método, por ejemplo:
>>> class A(object): ... @classmethod ... def foo(cls): ... print cls ... >>> A.foo() # note this is called directly on the class <class '__main__.A'>fuente
El ejemplo de la página web parece funcionar tal como se publicó. ¿
do_somethingCreó también un método para la superclase pero no lo convirtió en un método de clase? Algo como esto te dará ese error:>>> class A(object): ... def do_something(cls): ... print cls ... # do_something = classmethod(do_something) ... >>> class B(A): ... def do_something(cls): ... super(B, cls).do_something() ... do_something = classmethod(do_something) ... >>> B().do_something() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in do_something TypeError: unbound method do_something() must be called with B instance as first argument (got nothing instead)fuente
superllamada en el método B do_something es llamar a un método con ese nombre en una de sus superclases. Si no hay uno en A (o en Object), la llamada B (). Do_something () falla consuper object has no attribute do_something. ~ unutbu señala con razón que el ejemplo del documento es defectuoso.Creo que he entendido el punto ahora gracias a este hermoso sitio y a esta hermosa comunidad.
Si no le importa, corríjame si me equivoco con los métodos de clase (que ahora estoy tratando de entender completamente):
# EXAMPLE #1 >>> class A(object): ... def foo(cls): ... print cls ... foo = classmethod(foo) ... >>> a = A() >>> a.foo() # THIS IS THE CLASS ITSELF (__class__) class '__main__.A' # EXAMPLE #2 # SAME AS ABOVE (With new @decorator) >>> class A(object): ... @classmethod ... def foo(cls): ... print cls ... >>> a = A() >>> a.foo() class '__main__.A' # EXAMPLE #3 >>> class B(object): ... def foo(self): ... print self ... >>> b = B() >>> b.foo() # THIS IS THE INSTANCE WITH ADDRESS (self) __main__.B object at 0xb747a8ec >>>Espero que esta ilustración muestre ...
fuente