Utiliser super avec une méthode de classe
-
08-07-2019 - |
Question
J'essaie d'apprendre la fonction super () en Python.
Je pensais bien le comprendre avant de revenir à cet exemple (2.6) et de me retrouver coincé.
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)
>>>
Ce n'était pas ce à quoi je m'attendais lorsque j'ai lu cette ligne juste avant l'exemple:
Si nous utilisons une méthode de classe, nous n'avons pas d'instance avec laquelle appeler Super. Heureusement pour nous, super fonctionne même avec un type comme second argument. --- Le type peut être passé directement à super comme indiqué ci-dessous.
Ce qui est exactement ce que Python me dit n'est pas possible en disant que do_something () devrait être appelé avec une instance de B.
La solution
Parfois, les textes doivent être lus davantage pour la saveur de l'idée que pour les détails. C'est l'un de ces cas.
Dans la page associée , exemples 2.5 , 2.6 et 2.7 doivent tous utiliser la même méthode, do_your_stuff
. (Autrement dit, do_something
doit être remplacé par do_your_stuff
.)
En outre, a souligné Ned Deily , A.do_your_stuff
doit être un méthode de classe.
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
renvoie une méthode liée (voir note de bas de page 2 ). Puisque cls
a été passé en tant que second argument de super ()
, c'est cls
qui est lié à la méthode renvoyée. En d'autres termes, cls
est passé en tant que premier argument de la méthode do_your_stuff ()
de la classe A.
Pour réitérer: super (B, cls) .do_your_stuff ()
fait en sorte que la méthode A
de do_your_stuff
soit
appelé avec cls
passé en tant que premier argument. Pour que cela fonctionne, A
's
do_your_stuff
doit être une méthode de classe. La page liée ne mentionne pas cela,
mais c’est définitivement le cas.
PS. do_something = classmethod (do_something)
est l'ancienne méthode de création d'une méthode de classe.
La nouvelle méthode consiste à utiliser le décorateur @classmethod.
Notez que super (B, cls)
ne peut pas être remplacé par super (cls, cls)
. Cela pourrait conduire à des boucles infinies. Par exemple,
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()
lève RuntimeError: la profondeur de récursivité maximale est dépassée lors de l'appel d'un objet Python
.
Si cls
est C
, super (cls, cls)
recherche C.mro ()
la classe qui vient après C
.
In [161]: C.mro()
Out[161]: [__main__.C, __main__.B, __main__.A, object]
Puisque cette classe est B
, lorsque cls
est C
, super (cls, cls) .do_your_stuff ()
toujours appelle B.do_your_stuff
. Puisque super (cls, cls) .do_votre_stuff ()
est appelé à l'intérieur de B.do_votre_stuff
, vous appelez B.do_your_stuff
dans une boucle infinie. .
En Python3, le sous forme de 0 code argument de super
a été ajouté pour que super (B, cls)
puisse être remplacé par super ()
, et Python3 déterminera dans le contexte que super ( )
dans la définition de classe B
doit être équivalent à super (B, cls)
.
Mais super (cls, cls)
(ou pour des raisons similaires, super (type (self), self)
) n'est jamais correct.
Autres conseils
En Python 3, vous pouvez ignorer la spécification des arguments pour 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."
J'ai mis à jour l'article pour le rendre un peu plus clair: Attributs et méthodes Python # Super
Votre exemple d'utilisation de la méthode de classe ci-dessus montre ce qu'est une méthode de classe: elle passe la classe elle-même au lieu de l'instance comme premier paramètre. Mais vous n’avez même pas besoin d’une instance pour appeler la méthode, par exemple:
>>> class A(object):
... @classmethod
... def foo(cls):
... print cls
...
>>> A.foo() # note this is called directly on the class
<class '__main__.A'>
L'exemple de la page Web semble fonctionner tel que publié. Avez-vous également créé une méthode do_something
pour la super-classe, mais sans en faire une méthode de classe? Quelque chose comme ça va vous donner cette erreur:
>>> 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)
Je pense avoir compris le sens maintenant grâce à ce site magnifique et à cette belle communauté.
Si cela ne vous dérange pas, corrigez-moi si je me trompe sur les méthodes de classe (que j'essaie maintenant de bien comprendre):
# 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
>>>
J'espère que cette illustration montre ..