web-dev-qa-db-fra.com

interaction super () et @staticmethod

Super () n'est-il pas destiné à être utilisé avec des méthodes statiques?

Quand j'essaye quelque chose comme

class First(object):
  @staticmethod
  def getlist():
    return ['first']

class Second(First):
  @staticmethod
  def getlist():
    l = super(Second).getlist()
    l.append('second')
    return l

a = Second.getlist()
print a

J'obtiens l'erreur suivante

Traceback (most recent call last):
  File "asdf.py", line 13, in <module>
    a = Second.getlist()
  File "asdf.py", line 9, in getlist
    l = super(Second).getlist()
AttributeError: 'super' object has no attribute 'getlist'

Si je change les méthodes statiques en méthodes de classe et que je passe l'instance de classe à super (), les choses fonctionnent bien. Suis-je en train d'appeler super (type) incorrectement ou y a-t-il quelque chose qui me manque?

48
Ben

La réponse courte à

Suis-je en train d'appeler super (type) incorrectement ou y a-t-il quelque chose qui me manque?

est: oui, vous l'appelez incorrectement ... ET (en effet, parce que ) il y a quelque chose qui vous manque.

Mais ne vous sentez pas mal; c'est un sujet extrêmement difficile.

documentation note que

Si le deuxième argument est omis, le super objet renvoyé n'est pas lié.

Le cas d'utilisation des objets non liés super est extrêmement étroit et rare. Voir ces articles de Michele Simionato pour sa discussion sur super():

En outre, il plaide fortement pour la suppression de super non lié de Python 3 ici .

J'ai dit que vous l'appeliez "incorrectement" (bien que l'exactitude soit largement dénuée de sens sans contexte et qu'un exemple de jouet ne donne pas beaucoup de contexte). Parce que non lié super est si rare, et peut-être simplement carrément injustifié, comme le soutient Simionato, la manière "correcte" d'utiliser super() est de fournir le deuxième argument.

Dans votre cas, le moyen le plus simple de faire fonctionner votre exemple est

class First(object):
  @staticmethod
  def getlist():
    return ['first']

class Second(First):
  @staticmethod
  def getlist():
    l = super(Second, Second).getlist()  # note the 2nd argument
    l.append('second')
    return l

a = Second.getlist()
print a

Si vous pensez que c'est drôle de cette façon, vous ne vous trompez pas. Mais je pense que ce que la plupart des gens attendent quand ils voient super(X) (ou espèrent quand ils l'essayeront dans leur propre code), c'est ce que Python vous donne si vous le faites super(X, X).

50
John Y

Lorsque vous appelez une méthode normale sur une instance d'objet, la méthode reçoit l'instance d'objet comme premier paramètre. Il peut obtenir la classe de l'objet hte et sa classe parent, il est donc logique d'appeler super.

Lorsque vous appelez une méthode classmethod sur une instance d'objet ou sur une classe, la méthode reçoit la classe comme premier paramètre. Il peut obtenir la classe parente, il est donc logique d'appeler super.

Mais lorsque vous appelez une méthode staticmethod, la méthode ne reçoit rien, et n'a aucun moyen de savoir à partir de quel objet ou classe elle a été appelée. C'est la raison pour laquelle vous ne pouvez pas accéder à super dans une méthode statique.

1
Serge Ballesta