343 votes

super() lève "TypeError : must be type, not classbj" pour les classes d'un nouveau style.

L'utilisation suivante de super() soulève une TypeError : pourquoi ?

>>> from  HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
...     def __init__(self):
...         super(TextParser, self).__init__()
...         self.all_data = []
...         
>>> TextParser()
(...)
TypeError: must be type, not classobj

Il existe une question similaire sur StackOverflow : Python super() soulève TypeError où l'erreur s'explique par le fait que la classe utilisateur n'est pas une classe de type nouveau. Cependant, la classe ci-dessus est une classe de style nouveau, car elle hérite de object :

>>> isinstance(HTMLParser(), object)
True

Qu'est-ce que je rate ? Comment puis-je utiliser super() ici ?

Utilisation de HTMLParser.__init__(self) au lieu de super(TextParser, self).__init__() fonctionnerait, mais j'aimerais comprendre le TypeError.

PS : Joachim a fait remarquer que le fait d'être une instance de classe de nouveau style n'est pas équivalent au fait d'être une instance de classe de nouveau style. object . J'ai lu le contraire plusieurs fois, d'où ma confusion (exemple de test d'instance de classe nouveau style basé sur object test d'instance : https://stackoverflow.com/revisions/2655651/3 ).

250voto

EOL Points 24342

D'accord, c'est l'habituel " super() ne peut pas être utilisé avec une classe de style ancien".

Cependant, le point important est que le bon test pour "est-ce un nouveau style instance (c'est-à-dire l'objet) ? " est

>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False

et non (comme dans la question) :

>>> isinstance(instance, object)
True

Para classes le test correct "est-ce une classe d'un nouveau style" est :

>>> issubclass(OldStyle, object)  # OldStyle is not a new-style class
False
>>> issubclass(int, object)  # int is a new-style class
True

En point crucial est qu'avec les classes de l'ancien style, le classe d'une instance et de son type sont distincts. Ici, OldStyle().__class__ es OldStyle qui n'hérite pas de object alors que type(OldStyle()) es el instance type, qui fait hériter de object . Fondamentalement, une classe à l'ancienne crée simplement des objets de type instance (alors qu'une classe de style nouveau crée des objets dont le type est la classe elle-même). C'est probablement la raison pour laquelle l'instance OldStyle() est un object : son type() hérite de object (le fait que sa classe ne pas hériter de object ne compte pas : les classes de type ancien construisent simplement de nouveaux objets de type instance ). Référence partielle : https://stackoverflow.com/a/9699961/42973 .

PS : La différence entre une classe de style nouveau et une classe de style ancien peut également être vue avec :

>>> type(OldStyle)  # OldStyle creates objects but is not itself a type
classobj
>>> isinstance(OldStyle, type)
False
>>> type(int)  # A new-style class is a type
type

(les classes à l'ancienne sont pas ils ne peuvent donc pas être le type de leurs instances).

212voto

Colin Su Points 1322

Super() ne peut être utilisé que dans les classes de type nouveau, ce qui signifie que la classe racine doit hériter de la classe "objet".

Par exemple, la classe supérieure doit être comme ceci :

class SomeClass(object):
    def __init__(self):
        ....

pas

class SomeClass():
    def __init__(self):
        ....

Donc, la solution est d'appeler le parent init directement, comme ceci :

class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []

29voto

Valentin Lorentz Points 1456

Vous pouvez également utiliser class TextParser(HTMLParser, object): . Cela rend TextParser a nouveau style et super() peut être utilisé.

17voto

Joachim Pileborg Points 121221

Si vous regardez l'arbre d'héritage (dans la version 2.6), HTMLParser hérite de SGMLParser qui hérite de ParserBase dont n'a pas hérite de object . Par exemple, HTMLParser est une classe de type ancien.

A propos de votre contrôle avec isinstance J'ai fait un test rapide en ipython :

In \[1\]: class A:
   ...:     pass
   ...: 

In \[2\]: isinstance(A, object)
Out\[2\]: True

Même si une classe est une classe de style ancien, elle reste une instance de object .

5voto

Jacob Abraham Points 49

La manière correcte de procéder est la suivante dans les classes de l'ancien style qui n'héritent pas de 'object'.

class A:
    def foo(self):
        return "Hi there"

class B(A):
    def foo(self, name):
        return A.foo(self) + name

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X