对于新式类,super()引发“TypeError:必须是type,而不是classobj”

时间:2012-03-14 08:59:03

标签: python superclass super typeerror

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() raises 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)。

7 个答案:

答案 0 :(得分:241)

好吧,这是通常的“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__OldStyle,不会从object继承,而type(OldStyle())instance类型, 继承来自object。基本上,旧式类只创建类型为instance的对象(而新式类创建类型为类本身的对象)。这可能是实例OldStyle()object的原因:它的type()继承自object(其类继承自object {1}}不计算:旧式类只构造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

(旧式类不是类型,因此它们不能是其实例的类型。)

答案 1 :(得分:195)

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 = []

答案 2 :(得分:27)

您也可以使用class TextParser(HTMLParser, object):。这使得TextParser成为新式类,并且可以使用super()

答案 3 :(得分:21)

问题在于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

答案 4 :(得分:17)

如果查看继承树(在2.6版本中),HTMLParser继承自SGMLParser继承自{em> 继承自ParserBase的{​​{1}} {1}}。即HTMLParser是一个旧式的类。

关于您使用object进行检查,我在ipython中进行了快速测试:

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

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

即使一个类是旧式类,它仍然是isinstance的一个实例。

答案 5 :(得分:5)

正确的方法是在不继承“object”的旧式类中执行以下操作

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

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

答案 6 :(得分:0)

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
(...)

只是让我根据需要返回解析结果。