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

Eri*_*got 331 python super typeerror superclass

以下使用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
Run Code Online (Sandbox Code Playgroud)

StackOverflow上有一个类似的问题:Python super()引发TypeError,其中错误的解释是用户类不是新式类.但是,上面的类是一个新式的类,因为它继承自object:

>>> isinstance(HTMLParser(), object)
True
Run Code Online (Sandbox Code Playgroud)

我错过了什么?我怎么用super(),在这里?

使用HTMLParser.__init__(self)而不是super(TextParser, self).__init__()工作,但我想了解TypeError.

PS:Joachim指出,作为一个新式的实例并不等同于一个object.我多次反复阅读,因此我的困惑(基于object实例测试的新式类实例测试示例:https://stackoverflow.com/revisions/2655651/3).

Eri*_*got 244

好吧,这是通常的" super()不能用于旧式的课程".

然而,重要的一点是正确的测试 "这是一个新风格的实例(即对象)?" 是

>>> class OldStyle: pass
>>> instance = OldStyle()
>>> issubclass(instance.__class__, object)
False
Run Code Online (Sandbox Code Playgroud)

而不是(如在问题中):

>>> isinstance(instance, object)
True
Run Code Online (Sandbox Code Playgroud)

对于,正确的"这是一个新式的类"测试是:

>>> issubclass(OldStyle, object)  # OldStyle is not a new-style class
False
>>> issubclass(int, object)  # int is a new-style class
True
Run Code Online (Sandbox Code Playgroud)

关键的一点是,与老式类的的实例和它的类型是不同的.这里,OldStyle().__class__OldStyle,不继承object,同时type(OldStyle())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
Run Code Online (Sandbox Code Playgroud)

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

  • 很荒谬的是,2.7.x中的python标准库*仍然*不会从`object`继承,因此通过代理搞砸了你. (27认同)
  • 这就是我们现在拥有Python 3的原因之一. (11认同)
  • BTW:`(Oldstyle().__ class__是Oldstyle)`是'True` (2认同)
  • @Tino:的确,但是`OldStyle().__ class__`的目的是展示如何测试*object*(`OldStyle()`)是否来自旧式类.只考虑新风格的类,人们可能会尝试使用`isinstance(OldStyle(),object)来进行测试. (2认同)
  • @NickBastin - 这不是巧合.这一切都是为了将​​每个人都推向Python 3.其中"一切都很好".但是 - 告诫者 - 它只是诱饵和转换. (2认同)

Col*_* Su 198

super()只能在new-style类中使用,这意味着root类需要从'object'类继承.

例如,顶级类需要像这样:

class SomeClass(object):
    def __init__(self):
        ....
Run Code Online (Sandbox Code Playgroud)

class SomeClass():
    def __init__(self):
        ....
Run Code Online (Sandbox Code Playgroud)

所以,解决方案是直接调用父的init方法,就像这样:

class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,我必须这样做:HTMLParser .__ init __(self)我很好奇你的上一个例子是否有效? (8认同)

Val*_*ntz 28

你也可以使用class TextParser(HTMLParser, object):.这使得TextParser一个新式的类,并super()可以使用.


小智 22

问题是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
Run Code Online (Sandbox Code Playgroud)

仔细研究后发现:

>>> type(myclass)
classobj
Run Code Online (Sandbox Code Playgroud)

但:

>>> class newstyle(object): pass

>>> type(newstyle)
type    
Run Code Online (Sandbox Code Playgroud)

因此,您的问题的解决方案是从对象以及HTMLParser继承.但要确保对象在MRO类中排在最后:

>>> class myclass(oldstyle, object):
...     def __init__(self): super(myclass, self).__init__()

>>> myclass().os
True
Run Code Online (Sandbox Code Playgroud)


Som*_*ude 17

如果你看一下继承树(2.6版本),HTMLParser继承了SGMLParser它继承自ParserBase从继承object.即HTMLParser是一个旧式的类.

关于你的检查isinstance,我在ipython中做了一个快速测试:

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

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

即使一个类是旧式类,它仍然是一个实例object.

  • PS:最好的测试似乎是`issubclass(HTMLParser,object)`,返回False. (5认同)
  • 我相信正确的测试应该是`isinstance(A(),object)`,而不是`isinstance(A,object)`,不是吗?对于后者,你正在测试*class*`A`是否是`object`,而问题是'A`的*instances*是否是`object`,对吗? (2认同)

Jac*_*ham 5

正确的方法是在旧式类中继承"对象"

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

class B(A):
    def foo(self, name):
        return A.foo(self) + name
Run Code Online (Sandbox Code Playgroud)