簡體   English   中英

對於新式類,super()引發“TypeError:必須是type,而不是classobj”

[英]super() raises “TypeError: must be type, not classobj” for new-style class

以下使用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 )。

好吧,這是通常的“ 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

(舊式類不是類型,因此它們不能是它們實例的類型)。

super()只能在new-style類中使用,這意味着root類需要從'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 = []

您還可以使用class TextParser(HTMLParser, object): 這使得TextParser成為一種新式的類,並且可以使用super()

問題是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

如果查看繼承樹(在2.6版本中), HTMLParser繼承自從ParserBase繼承的SGMLParser ,它object繼承。 即HTMLParser是一個舊式的類。

關於你的isinstance ,我在ipython中做了一個快速測試:

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

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

即使一個類是舊式類,它仍然是一個object的實例。

正確的方法是在舊式類中繼承“對象”

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

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

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

剛剛根據需要解析了解析結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM