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)是可以的,但我想了解TypeError。

PS:Joachim指出这是一种新方法-style-class实例并不等同于super(TextParser, self).__init__()。我读了很多相反的书,因此感到困惑(基于object实例测试的新型类实例测试的示例:https://stackoverflow.com/revisions/2655651/3)。

评论

感谢您的提问和回答。我想知道为什么2.7的super .__ doc__没有提及新旧样式!

谢谢。 :)文档字符串通常比完整的HTML版本的文档包含更少的信息。 HTML文档(docs.python.org/library/functions.html#super)中提到了super()仅适用于新型类(和对象)的事实。

python super()的可能重复项引发TypeError!为什么?

这不是重复的内容(请参阅更新的问题和接受的答案)。

#1 楼

好吧,这是通常的“ 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的事实不计算在内:旧式类仅构造了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


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

评论


这就是我们现在拥有Python 3的原因之一。

–史蒂文·鲁姆巴尔斯基(Steven Rumbalski)
2012年3月15日15:09

顺便说一句:(Oldstyle().__ class__是Oldstyle)是True

– Tino
2012年10月28日16:13



@Tino:的确如此,但是OldStyle().__ class__的要点是显示如何测试对象(OldStyle())是否来自旧类。考虑到只有新式类,可能会倾向于使用isinstance(OldStyle(),object)进行测试。

– Eric O Lebigot
13年3月3日,11:49



荒谬的是,2.7.x中仍然有多少python标准库没有从对象继承,因此代理会给您带来麻烦。

–尼克·巴斯汀(Nick Bastin)
13-10-12在4:23

@NickBastin-这不是巧合。所有这些都是为了将​​所有人推入Python3。在这里,“一切都很好”。但是-告急者-只是诱饵和开关。

– Tomasz Gandor
14-10-20在12:57

#2 楼

super()只能在新型类中使用,这意味着根类需要从'object'类继承。

例如,顶层类需要这样:

 class SomeClass(object):
    def __init__(self):
        ....
 


not

 class SomeClass():
    def __init__(self):
        ....
 


因此,解决方案是直接调用父级的init方法,如下所示:

 class TextParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.all_data = []
 


评论


对我来说,我必须这样做:HTMLParser .__ init __(self)我很好奇您的上一个示例是否有效?

–聊天
2012年11月27日在1:31

@EOL是什么意思? jeffp刚刚指出,由于HTMLParser .__ init __()调用中缺少自我参数,此答案中给出的代码是错误的。

–彼得·多布罗格斯特(Piotr Dobrogost)
13年5月24日15:00



@PiotrDobrogost:对不起,我的评论是关于LittleQ的答案,而不是关于jeffp的(好)观点。

– Eric O Lebigot
13年5月25日在9:14

@jeffp对不起,这是一个错字,我只是在SO上打出来,但没有测试,我的错。感谢您的纠正

–苏琳(Colin Su)
2013年9月25日上午8:18

支持适用于现有代码的修复程序,例如python2.6中的logging.Formatter

–大卫·雷诺兹(David Reynolds)
2014年4月25日在10:23

#3 楼

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

评论


我的反对,因为添加对象的继承是一个好主意。 (也就是说,此答案并未解决理解该问题的TypeError的问题。)

– Eric O Lebigot
13年5月12日在1:10

#4 楼

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


评论


有效点,但是它们已经在先前的答案中。另外,重要的是,myclass是否从对象继承(即isinstance(myclass,object)是否为true —它为false),而不是检查type(myclass)。

– Eric O Lebigot
15-10-18在15:08



#5 楼

如果查看继承树(在2.6版中),则HTMLParser继承自SGMLParser,后者继承自ParserBase,而不继承自object。即HTMLParser是一个老式的类。

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

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

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


class是老式的类,它仍然是object的实例。

评论


我认为正确的测试应该是isinstance(A(),object),而不是isinstance(A,object),不是吗?使用后者,您正在测试类A是否是对象,而问题是A的实例是否是对象,对吗?

– Eric O Lebigot
2012年3月14日9:40



PS:最好的测试似乎是issubclass(HTMLParser,object),它返回False。

– Eric O Lebigot
2012年3月14日在9:51

#6 楼

正确的方法是在不继承自'object'的旧类中进行以下操作

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

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


评论


在问题中,已经提到了这种方法:问题是要理解为什么会产生错误消息,而不是使其消失(特别是以此方式)。

– Eric O Lebigot
2014年2月25日在2:23

此外,在我们要调用存储状态的类A实例的情况下,此解决方案将不起作用。

– Tashuhka
2015年6月9日15:37

#7 楼

FWIW,尽管我不是Python专家,但我对此还是不满意的。