![](/img/trans.png)
[英]super() fails with error: TypeError "argument 1 must be type, not classobj" when parent does not inherit from object
[英]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.