L'utilisation suivante de super()
génère une erreur 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 () déclenche TypeError , où l'erreur est expliquée par le fait que la classe user n'est pas une classe de style 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 utiliser super()
ici?
Utiliser HTMLParser.__init__(self)
au lieu de super(TextParser, self).__init__()
fonctionnerait, mais j'aimerais comprendre le TypeError.
PS: Joachim a souligné qu'être une instance de classe de style nouvelle n'équivaut pas à être un object
. J'ai lu l'inverse plusieurs fois, d'où ma confusion (exemple de test d'instance de classe de style nouveau basé sur le test d'instance object
: https://stackoverflow.com/revisions/2655651/ ) .
Bon, c'est l'habituel "super()
ne peut pas être utilisé avec une classe de style ancien".
Cependant, le point important est que le test correct pour "est-ce une instance de nouveau style (objet)? " est
>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False
et non (comme dans la question):
>>> isinstance(instance, object)
True
Pour classes , le test correct "est-ce une classe de style nouveau" est:
>>> issubclass(OldStyle, object) # OldStyle is not a new-style class
False
>>> issubclass(int, object) # int is a new-style class
True
Le point crucial est que, avec les classes de style ancien, la classe d'une instance et ses type sont distincts. Ici, OldStyle().__class__
est OldStyle
, qui n’hérite pas de object
, alors que type(OldStyle())
est le type instance
, que fait hériter de object
. En gros, une classe de style ancien 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 pourquoi l'instance OldStyle()
est une object
: sa type()
hérite de object
(le fait que sa classe ne ne soit pas hériter de object
ne compte pas: les classes de style 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 de style ancien sont pas des types , elles ne peuvent donc pas être le type de leurs instances).
super () ne peut être utilisé que dans les classes new-style, ce qui signifie que la classe racine doit hériter de la classe 'object'.
Par exemple, la classe supérieure doit être comme ceci:
class SomeClass(object):
def __init__(self):
....
ne pas
class SomeClass():
def __init__(self):
....
La solution consiste donc à appeler directement la méthode init du parent, comme suit:
class TextParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.all_data = []
Vous pouvez également utiliser class TextParser(HTMLParser, object):
. Cela fait de TextParser
une classe new-style, et super()
peut être utilisé.
Le problème est que super
a besoin d'un object
en tant qu'ancêtre:
>>> class oldstyle:
... def __init__(self): self.os = True
>>> class myclass(oldstyle):
... def __init__(self): super(myclass, self).__init__()
>>> myclass()
TypeError: must be type, not classobj
En regardant de plus près, on trouve:
>>> type(myclass)
classobj
Mais:
>>> class newstyle(object): pass
>>> type(newstyle)
type
La solution à votre problème serait donc d’hériter d’objet aussi bien que de HTMLParser. Mais assurez-vous que l'objet arrive en dernier dans les classes MRO:
>>> class myclass(oldstyle, object):
... def __init__(self): super(myclass, self).__init__()
>>> myclass().os
True
Si vous regardez l'arbre de l'héritage (dans la version 2.6), HTMLParser
hérite de SGMLParser
qui hérite de ParserBase
qui ne fait pas hérite de object
. C'est à dire. HTMLParser est une classe de style ancien.
A propos de votre vérification avec isinstance
, j’ai fait un test rapide sous ipython:
Dans [1]: classe A: ...: passer ...: Dans [2]: isinstance (A , objet) Out [2]: Vrai
Même si une classe est une classe de style ancien, elle reste une instance de object
.
la bonne façon de faire sera comme suit dans les classes de style ancien qui n'héritent pas de 'objet'
class A:
def foo(self):
return "Hi there"
class B(A):
def foo(self, name):
return A.foo(self) + name
FWIW et bien que je ne sois pas un Python gourou je me suis débrouillé avec ça
>>> class TextParser(HTMLParser):
... def handle_starttag(self, tag, attrs):
... if tag == "b":
... self.all_data.append("bold")
... else:
... self.all_data.append("other")
...
...
>>> p = TextParser()
>>> p.all_data = []
>>> p.feed(text)
>>> print p.all_data
(...)
Je viens de recevoir les résultats d'analyse au besoin.