The following use of super() raises a TypeError: why?
>>> from HTMLParser import HTMLParser >>> class TextParser(HTMLParser): ... def __init__(self): ... super(TextParser, self).__init__() ... self.all_data = [] ... >>> TextParser() (...) TypeError: must be type, not classobj
There is a similar question on StackOverflow: Python super() raises TypeError, where the error is explained by the fact that the user class is not a new-style class. However, the class above is a new-style class, as it inherits from object:
>>> isinstance(HTMLParser(), object) True
What am I missing? How can I use super(), here?
Using HTMLParser.__init__(self) instead of super(TextParser, self).__init__() would work, but I would like to understand the TypeError.
PS: Joachim pointed out that being a new-style-class instance is not equivalent to being an object. I read the opposite many times, hence my confusion (example of new-style class instance test based on object instance test: https://stackoverflow.com/revisions/2655651/3).
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Alright, it’s the usual “super() cannot be used with an old-style class”.
However, the important point is that the correct test for “is this a new-style instance (i.e. object)?” is
>>> class OldStyle: pass >>> instance = OldStyle() >>> issubclass(instance.__class__, object) False
and not (as in the question):
>>> isinstance(instance, object) True
For classes, the correct “is this a new-style class” test is:
>>> issubclass(OldStyle, object) # OldStyle is not a new-style class False >>> issubclass(int, object) # int is a new-style class True
The crucial point is that with old-style classes, the class of an instance and its type are distinct. Here, OldStyle().__class__ is OldStyle, which does not inherit from object, while type(OldStyle()) is the instance type, which does inherit from object. Basically, an old-style class just creates objects of type instance (whereas a new-style class creates objects whose type is the class itself). This is probably why the instance OldStyle() is an object: its type() inherits from object (the fact that its class does not inherit from object does not count: old-style classes merely construct new objects of type instance). Partial reference: https://stackoverflow.com/a/9699961/42973.
PS: The difference between a new-style class and an old-style one can also be seen with:
>>> 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
(old-style classes are not types, so they cannot be the type of their instances).
Method 2
super() can be used only in the new-style classes, which means the root class needs to inherit from the ‘object’ class.
For example, the top class need to be like this:
class SomeClass(object):
def __init__(self):
....
not
class SomeClass():
def __init__(self):
....
So, the solution is that call the parent’s init method directly, like this way:
class TextParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.all_data = []
Method 3
You can also use class TextParser(HTMLParser, object):. This makes TextParser a new-style class, and super() can be used.
Method 4
The problem is that super needs an object as an ancestor:
>>> 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
On closer examination one finds:
>>> type(myclass) classobj
But:
>>> class newstyle(object): pass >>> type(newstyle) type
So the solution to your problem would be to inherit from object as well as from HTMLParser.
But make sure object comes last in the classes MRO:
>>> class myclass(oldstyle, object): ... def __init__(self): super(myclass, self).__init__() >>> myclass().os True
Method 5
If you look at the inheritance tree (in version 2.6), HTMLParser inherits from SGMLParser which inherits from ParserBase which doesn’t inherits from object. I.e. HTMLParser is an old-style class.
About your checking with isinstance, I did a quick test in ipython:
In [1]: class A: ...: pass ...: In [2]: isinstance(A, object) Out[2]: True
Even if a class is old-style class, it’s still an instance of object.
Method 6
the correct way to do will be as following in the old-style classes which doesn’t inherit from ‘object’
class A:
def foo(self):
return "Hi there"
class B(A):
def foo(self, name):
return A.foo(self) + name
Method 7
FWIW and though I’m no Python guru I got by with this
>>> 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
(...)
Just got me the parse results back as needed.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0