以下の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
classesの場合、正しい「is this a new-style class」テストは次のとおりです。
>>> issubclass(OldStyle, object) # OldStyle is not a new-style class
False
>>> issubclass(int, object) # int is a new-style class
True
重要なポイントは、古いスタイルのクラスでは、インスタンスのclassとそのtypeは区別されます。ここで、OldStyle().__class__
はOldStyle
から継承されないobject
であり、type(OldStyle())
はinstance
タイプであり、doesobject
から継承します。基本的に、古いスタイルのクラスはタイプinstance
のオブジェクトを作成します(一方、新しいスタイルのクラスはタイプがクラス自体であるオブジェクトを作成します)。これがおそらくインスタンスOldStyle()
がobject
である理由です。そのtype()
はobject
を継承します(そのクラスはnotobject
を継承しません。古いスタイルのクラスは、単にinstance
)型の新しいオブジェクトを構築します。部分参照: https://stackoverflow.com/a/9699961/4297 。
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
(古いスタイルのクラスはnot型なので、インスタンスの型にすることはできません)。
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 = []
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
はSGMLParser
を継承しています。これはParserBase
を継承しています。これはdoes n'tはobject
を継承しています。つまりHTMLParserは古いスタイルのクラスです。
isinstance
を使用したチェックについて、ipythonで簡単なテストを行いました。
[1]:クラスA: ...:pass ...: In [2]:isinstance(A 、オブジェクト) Out [2]:True
クラスが古いスタイルのクラスであっても、object
のインスタンスのままです。
正しいやり方は '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
(...)
解析結果を必要に応じて返してください。