J'essaie d'apprendre la fonction super () en Python.
Je pensais l'avoir compris jusqu'à ce que je revienne sur cet exemple (2.6) et que je me retrouve 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 en lisant 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 deuxième argument. --- Le type peut être transmis directement à super comme indiqué ci-dessous.
C'est exactement ce que Python me dit que ce n'est pas possible en disant que do_something () devrait être appelé avec une instance de B.
Parfois, les textes doivent être lus davantage pour la saveur de l'idée plutôt que pour les détails. C'est l'un de ces cas.
Dans la page liée , les exemples 2.5, 2.6 et 2.7 doivent tous utiliser une seule méthode, do_your_stuff
. (Autrement dit, do_something
Doit être remplacé par do_your_stuff
.)
De plus, comme Ned Deily l'a souligné , A.do_your_stuff
Doit être une 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 bound (voir note 2 ). Puisque cls
a été passé comme deuxième argument à super()
, c'est cls
qui est lié à la méthode retournée. En d'autres termes, cls
est passé comme premier argument à la méthode do_your_stuff()
de la classe A.
Pour réitérer: super(B, cls).do_your_stuff()
provoque l'appel de la méthode do_your_stuff
De A
avec cls
passé comme premier argument. Pour que cela fonctionne, le do_your_stuff
De A
doit être une méthode de classe. La page liée ne le mentionne pas, mais c'est définitivement le cas.
PS. do_something = classmethod(do_something)
est l'ancienne façon de créer une méthode de classe. La nouvelle (er) façon consiste à utiliser le décorateur @classmethod.
Notez que super(B, cls)
ne peut pas être remplacée 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()
augmentera RuntimeError: maximum recursion depth exceeded while calling a Python object
.
Si cls
est C
, alors super(cls, cls)
recherche C.mro()
pour 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_your_stuff()
est appelée dans B.do_your_stuff
, Vous finissez par appeler B.do_your_stuff
Dans une boucle infinie.
En Python3, la forme -argument de super
a été ajoutée pour que super(B, cls)
puisse être remplacée par super()
, et Python3 trouvera contexte que super()
dans la définition de class B
devrait être équivalent à super(B, cls)
.
Mais en aucun cas super(cls, cls)
(ou pour des raisons similaires, super(type(self), self)
) n'est jamais correct.
Dans 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 transmet 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 créé un do_something
méthode pour la superclasse aussi mais pas en faire une méthode de classe? Quelque chose comme ça vous donnera 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 que j'ai compris le point maintenant grâce à ce beau site et à cette belle communauté.
Si cela ne vous dérange pas, veuillez me corriger si je me trompe sur les méthodes de classe (que j'essaie maintenant de comprendre pleinement):
# 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 ..