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_something
debería cambiarse ado_your_stuff
.)Además, como señaló Ned Deily ,
A.do_your_stuff
tiene 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_stuff
devuelve un método enlazado (ver nota al pie 2 ). Dado quecls
se pasó como segundo argumento asuper()
, es elcls
que se vincula al método devuelto. En otras palabras,cls
se pasa como primer argumento al métododo_your_stuff()
de la clase A.Para reiterar:
super(B, cls).do_your_stuff()
causasA
'sdo_your_stuff
método para ser llamados concls
pasado como primer argumento. Para que eso funcione,A
'sdo_your_stuff
tiene 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
cls
es 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
, cuandocls
esC
,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_stuff
en un bucle infinito.En Python3, se agregó la forma de argumento 0 de, por
super
lo quesuper(B, cls)
podría reemplazarse porsuper()
, y Python3 averiguará a partir del contexto quesuper()
en la definición declass B
deberí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 arguments
Actualicé 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_something
Creó 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
super
llamada 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