问题:对于新样式的类,super()引发“ TypeError:必须为类型,而不是classobj”
以下用法super()
引发TypeError:为什么?
>>> from HTMLParser import HTMLParser
>>> class TextParser(HTMLParser):
... def __init__(self):
... super(TextParser, self).__init__()
... self.all_data = []
...
>>> TextParser()
(...)
TypeError: must be type, not classobj
在StackOverflow上有一个类似的问题:Python super()引发TypeError,该错误由用户类不是新型类的事实来解释。但是,上面的类是一种新式的类,因为它继承自object
:
>>> isinstance(HTMLParser(), object)
True
我想念什么?我如何super()
在这里使用?
使用HTMLParser.__init__(self)
代替super(TextParser, self).__init__()
可以工作,但是我想了解TypeError。
PS:Joachim指出,成为一个新类实例并不等同于成为一个实例object
。我读了很多相反的书,因此感到困惑(基于object
实例测试的新型类实例测试的示例:https : //stackoverflow.com/revisions/2655651/3)。
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).
回答 0
好吧,这是通常的“ super()
不能与老式类一起使用”。
但是,重要的一点是对“这是一个新的实例(即对象)吗?” 的正确测试。是
>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False
而不是(如问题所示):
>>> isinstance(instance, object)
True
对于类,正确的“这是新型类”测试是:
>>> issubclass(OldStyle, object) # OldStyle is not a new-style class
False
>>> issubclass(int, object) # int is a new-style class
True
在关键的一点是,与老式类的类的实例和它的类型是不同的。在这里,OldStyle().__class__
is OldStyle
,它不继承自object
,而type(OldStyle())
is instance
类型,它确实继承自object
。基本上,旧式类仅创建类型的对象instance
(而新式类将创建类型为类本身的对象)。这大概就是为什么实例OldStyle()
是object
:其type()
从继承object
(事实上,它的类并没有继承object
不计数:老式类只是构建类型的新对象instance
)。部分参考:https://stackoverflow.com/a/9699961/42973。
PS:新式类和旧式类之间的区别还可以通过以下方式看到:
>>> 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
(旧式类不是类型,因此它们不能是其实例的类型)。
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).
回答 1
super()仅可用于新型类,这意味着根类需要从’object’类继承。
例如,顶级类需要像这样:
class SomeClass(object):
def __init__(self):
....
不
class SomeClass():
def __init__(self):
....
因此,解决方案是直接调用父级的init方法,如下所示:
class TextParser(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.all_data = []
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 = []
回答 2
您也可以使用class TextParser(HTMLParser, object):
。这将创建TextParser
一个新样式的类,并且super()
可以使用。
You can also use class TextParser(HTMLParser, object):
. This makes TextParser
a new-style class, and super()
can be used.
回答 3
问题是super
需要object
一个祖先:
>>> 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
经过仔细检查,发现:
>>> type(myclass)
classobj
但:
>>> class newstyle(object): pass
>>> type(newstyle)
type
因此,解决您的问题的方法是从对象以及HTMLParser继承。但是确保对象在MRO类中排在最后:
>>> class myclass(oldstyle, object):
... def __init__(self): super(myclass, self).__init__()
>>> myclass().os
True
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
回答 4
如果您查看继承树(在2.6版中),则HTMLParser
继承自SGMLParser
,继承自ParserBase
,而不继承自object
。即HTMLParser是一个老式的类。
关于您的检查isinstance
,我在ipython中进行了快速测试:
在[1]中:A类:
...:通过
...:
在[2]中:isinstance(A,object)
出[2]:是
即使一个类是老式类,它仍然是的一个实例object
。
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
.
回答 5
正确的方法是在不继承自’object’的旧类中执行以下操作
class A:
def foo(self):
return "Hi there"
class B(A):
def foo(self, name):
return A.foo(self) + name
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
回答 6
FWIW,尽管我不是Python专家,但我对此很满意
>>> 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
(...)
只是让我根据需要返回解析结果。
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.