super () échoue avec l'erreur: TypeError "l'argument 1 doit être de type, pas classobj" lorsque le parent n'hérite pas de l'objet

196

Je reçois une erreur que je ne peux pas comprendre. Un indice quel est le problème avec mon exemple de code?

class B:
    def meth(self, arg):
        print arg

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

J'ai obtenu l'exemple de code de test à l'aide de la méthode intégrée «super».

Voici l'erreur:

Traceback (most recent call last):
  File "./test.py", line 10, in ?
    print C().meth(1)
  File "./test.py", line 8, in meth
    super(C, self).meth(arg)
TypeError: super() argument 1 must be type, not classobj

Pour info, voici l'aide (super) de python lui-même:

Help on class super in module __builtin__:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
 |
Ehsan Foroughi
la source
la duplication possible de python super () déclenche TypeError! Pourquoi?
utilisateur
3
Meth ?? Est-ce un terme de programmation, ou ... vous savez? Précisez s'il vous plaît.
Cplusplusplus
3
@Cplusplusplus: signifie probablement méthode ;-)
ShadowFlame

Réponses:

333

Votre problème est que la classe B n'est pas déclarée en tant que classe "nouveau style". Changez-le comme ceci:

class B(object):

et ça marchera.

super()et tous les éléments de sous-classe / superclasse ne fonctionnent qu'avec des classes de nouveau style. Je vous recommande de prendre l'habitude de toujours taper(object) sur n'importe quelle définition de classe pour vous assurer qu'il s'agit d'une classe de nouveau style.

Les classes à l'ancienne (également appelées classes "classiques") sont toujours de type classobj; les classes de nouveau style sont de type type. C'est pourquoi vous avez reçu le message d'erreur que vous avez vu:

TypeError: super() argument 1 must be type, not classobj

Essayez ceci pour voir par vous-même:

class OldStyle:
    pass

class NewStyle(object):
    pass

print type(OldStyle)  # prints: <type 'classobj'>

print type(NewStyle) # prints <type 'type'>

Notez que dans Python 3.x, toutes les classes sont de nouveau style. Vous pouvez toujours utiliser la syntaxe des classes à l'ancienne, mais vous obtenez une classe à nouveau style. Donc, dans Python 3.x, vous n'aurez pas ce problème.

steveha
la source
intéressant, j'ai trouvé ce problème exact en exécutant bottle.py ( bottlepy.org ) qui génère une erreur similaire (TypeError: doit être de type, pas classobj) fonctionnant sur Py27 mais pas Py33.
bootload
Dans Python 3.x, il n'y a plus de classes "à l'ancienne". Le code utilisant la déclaration "old-style" déclare toujours une classe "new-style", donc cette erreur ne peut pas se produire dans Python 3.x.
steveha
1
Si vous ne pouvez pas modifier la classe B, vous devez alors modifier la classe A pour ne pas essayer d'utiliser super(); la classe A doit être conçue pour fonctionner avec une classe "à l'ancienne", et peut-être que la meilleure façon de le faire serait de faire de la classe A elle-même une classe "à l'ancienne". Bien sûr, je vous recommande de simplement mettre à niveau l'ensemble de votre programme pour qu'il s'exécute en Python 3.x, afin que toutes les classes soient de nouveau style, peu importe ce que vous faites; si cette option est disponible, c'est la meilleure option.
steveha
J'ai le même problème, mais ma classe de base est déclarée comme class B(object):. Je reçois cette erreur en raison de l'utilisation @mock.patch('module.B', autospec=B)juste avant mon scénario de test. Des réflexions sur la façon de résoudre ce problème?
MikeyE
154

De plus, si vous ne pouvez pas modifier la classe B, vous pouvez corriger l'erreur en utilisant l'héritage multiple.

class B:
    def meth(self, arg):
        print arg

class C(B, object):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)
frmdstryr
la source
16
Je n'ai pas pu m'empêcher de laisser un commentaire, celui-ci devrait être accepté comme réponse «standard».
workplaylifecycle
9
Pour les futurs googleurs bloqués sur Python 2.6: c'est la réponse que vous cherchez probablement! Lorsque vous ne pouvez pas modifier la classe de base (par exemple, vous sous-classe une classe de bibliothèque standard), ce changement dans votre propre classe corrige super ().
coredumperror
Cela a bien fonctionné pour moi, pouvez-vous quelqu'un expliquer comment cela fonctionne?
subro
@subro, cela fait de votre classe une classe "nouveau style" (où l'objet classe est de type type) tout en sous- classant toujours une classe "ancien style" (dont l'objet classe est de type classobj). super()fonctionne avec des classes de style nouveau mais pas avec des classes de style ancien.
MarSoft
réponse parfaite!
Tom
18

Si la version python est 3.X, ça va.

Je pense que votre version python est 2.X, le super fonctionnerait lors de l'ajout de ce code

__metaclass__ = type

donc le code est

__metaclass__ = type
class B:
    def meth(self, arg):
        print arg
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)
print C().meth(1)
yanghaogn
la source
4

J'ai également été confronté au problème publié lorsque j'ai utilisé python 2.7. Cela fonctionne très bien avec python 3.4

Pour le faire fonctionner en python 2.7, j'ai ajouté l' __metaclass__ = typeattribut en haut de mon programme et cela a fonctionné.

__metaclass__ : Il facilite la transition entre les classes à l'ancienne et les classes à nouveau style.

JON
la source