Python super () lève TypeError

109

Dans Python 2.5, le code suivant déclenche un TypeError:

>>> class X:
      def a(self):
        print "a"

>>> class Y(X):
      def a(self):
        super(Y,self).a()
        print "b"

>>> c = Y()
>>> c.a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in a
TypeError: super() argument 1 must be type, not classobj

Si je remplace le class Xpar class X(object), cela fonctionnera. Quelle est l'explication à cela?

Géo
la source
3
votre "cependant je remplace la classe X par la classe X (objet)" a résolu mon problème! Thanx
AliBZ

Réponses:

132

La raison en est que super()ne fonctionne que sur les classes de nouveau style , ce qui dans la série 2.x signifie s'étendre de object:

>>> class X(object):
        def a(self):
            print 'a'

>>> class Y(X):
        def a(self):
            super(Y, self).a()
            print 'b'

>>> c = Y()
>>> c.a()
a
b
Cody Brocious
la source
4
De quelle version de Python est-ce devenu le comportement par défaut?
Geo
6
2.2 était lorsque les classes de nouveau style ont été introduites, 3.0 est l'endroit où elles sont devenues la valeur par défaut.
Cody Brocious
7
@tsunami si vous voulez accéder à la superclasse, faites "Xa (self)"
James Brady
Je pense que vous m'avez mal compris . Triptyque. Je me souviens que j'utilisais une version python inférieure à 3.0, et je n'ai pas spécifiquement dit que ma classe hérite d'Object et que l'appel à super fonctionnait. C'est peut-être le comportement par défaut de la version 2.6? Juste en disant :)
Geo
Albâtre, il n'y a vraiment pas besoin de ça. Les classes de style nouveau ont un grand nombre d'avantages, pas seulement super. Les méthodes à l'ancienne ne devraient pas être promues.
Cody Brocious
14

De plus, n'utilisez pas super () sauf si vous devez le faire. Ce n'est pas la "bonne chose" générale à faire avec les classes de style nouveau que vous pourriez soupçonner.

Il y a des moments où vous vous attendez à un héritage multiple et vous pourriez le vouloir, mais jusqu'à ce que vous connaissiez les détails poilus du MRO, mieux vaut le laisser tranquille et s'en tenir à:

 X.a(self)
bobince
la source
2
est-ce correct parce que dans mes 6 mois de Python / Django, j'ai utilisé super comme la "bonne chose à faire"?
philgo20
1
Eh bien, cela ne vous fait pas de mal pour l'héritage unique en soi (sauf que c'est un peu plus lent), mais cela ne vous rapporte rien non plus. Vous devez concevoir toutes les méthodes qui doivent hériter de manière multiple (notamment __init__) pour passer les arguments de manière propre et sensée, sinon vous aurez des erreurs de type ou des problèmes de débogage pires lorsque quelqu'un essaie d'hériter de manière multiple en utilisant votre classe. À moins que vous n'ayez vraiment conçu pour prendre en charge MI de cette manière (ce qui est assez délicat), il est probablement préférable d'éviter l'implication superque la méthode est sûre MI.
bobince
3

Au cas où aucune des réponses ci-dessus ne le mentionnerait clairement. Votre classe parent doit hériter de "object", ce qui le transformerait essentiellement en une nouvelle classe de style.

# python 3.x:
class ClassName(object): # This is a new style class
    pass

class ClassName: # This is also a new style class ( implicit inheritance from object )
    pass

# Python 2.x:
class ClassName(object): # This is a new style class
    pass

class ClassName:         # This is a old style class
    pass
Abhi Tk
la source
Désolé, mais en Python 3.x votre deuxième exemple (héritage implicite) ne fonctionne pas vraiment dans le contexte du problème mentionné.
sophros
1

J'ai essayé les différentes méthodes Xa (); cependant, ils semblent nécessiter une instance de X pour exécuter a (), donc j'ai fait X (). a (self), qui semble plus complet que les réponses précédentes, du moins pour les applications que j'ai rencontrées. Cela ne semble pas être un bon moyen de gérer le problème car il y a une construction et une destruction inutiles, mais cela fonctionne bien.

Mon application spécifique était le module cmd.Cmd de Python, qui n'est évidemment pas un objet NewStyle pour une raison quelconque.

Résultat final:

X().a(self)
weberc2
la source