super()は、新しいスタイルのクラスに対して「TypeError:classobjではなく、typeでなければならない」を発生させます。


335

次の使用は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)。


3
質問と回答をありがとうございます。2.7 super.__doc__が古いスタイルと新しいスタイルについて何も触れていないのはなぜでしょうか。
ケルビン

ありがとう。:) docstringsは通常、ドキュメントの完全なHTMLバージョンよりも少ない情報を含みます。super()新しいスタイルのクラス(およびオブジェクト)でのみ機能するという事実は、HTMLドキュメント(docs.python.org/library/functions.html#super)で言及されています。
エリックOレビゴット2012


これは重複ではありません(更新された質問と承認された回答を参照してください)。
Eric O Lebigot 2014年

回答:


246

さて、通常の「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

(古いスタイルのクラスはタイプではないため、インスタンスのタイプにすることはできません)。


11
そして、これは私たちが今のPython 3を持っている理由の一つである
スティーブンRumbalski

2
ところで:(Oldstyle().__class__ is Oldstyle)isTrue
Tino

2
@Tino:確かに、しかしポイントはOldStyle().__class__オブジェクトOldStyle())が古いスタイルのクラスからのものかどうかをテストする方法を示すことです。新しいスタイルのクラスのみを念頭に置くと、isinstance(OldStyle(), object)代わりにテストを実行したくなるかもしれません。
Eric O Lebigot 2013

27
2.7.xにまだ残っているPython標準ライブラリのどれがから継承されないのかは、途方もないobjectことです。そのため、プロキシによってねじ込まれます。
Nick Bastin 2013年

2
@NickBastin-これは偶然ではありません。すべての人をPython 3にプッシュするために必要なことです。しかし、-空の注意点-それは餌とスイッチだけです。
Tomasz Gandor

204

super()は新しいスタイルのクラスでのみ使用できます。つまり、ルートクラスは「オブジェクト」クラスから継承する必要があります。

たとえば、最上位クラスは次のようにする必要があります。

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

ない

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

したがって、解決策は、次のように親のinitメソッドを直接呼び出すことです。

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

8
私のために、私はこれをしなければなりませんでした:HTMLParser .__ init __(self)私はあなたの最後の例がうまくいったかどうか知りたいですか?
chaimp

1
@EOLどういう意味ですか?jeffpはselfHTMLParser.__init__()呼び出しのパラメーターがないため、この回答で示されているコードが間違っていることを指摘しました。
Piotr Dobrogost 2013年

1
@PiotrDobrogost:申し訳ありませんが、私の発言はLittleQの回答についてであり、jeffpの(良い)ポイントについてではありませんでした。
エリックOレビゴット2013年

1
@jeffp申し訳ありません。タイプミスです。SOで入力するだけですが、テストしていません。私のせいです。修正してくれてありがとう
Colin Su

1
python2.6のlogging.Formatterなどの既存のコードで機能する修正に賛成します
David Reynolds

28

も使用できますclass TextParser(HTMLParser, object):。これによりTextParser新しいスタイルのクラスsuper()が作成され、使用できるようになります。


オブジェクトからの継承を追加するのは良い考えなので、私からの賛成票です。(とはいえ、この回答は質問のTypeErrorを理解する問題には対応していません。)
Eric O Lebigot 2013年

23

問題は、祖先としてが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

有効なポイントですが、それらはすでに以前の回答にあります。また、をチェックする代わりに、オブジェクトから継承するかどうか(つまり、trueであるかfalseであるか)がtype(myclass)重要です。myclassisinstance(myclass, object)
Eric O Lebigot

17

あなたが継承ツリーを見てみると(バージョン2.6で)、HTMLParserから継承SGMLParserからどの継承ParserBaseされていませんから継承object。つまり、HTMLParserは古いスタイルのクラスです。

でのチェックについてisinstance、私はipythonで簡単なテストを行いました:

[1]:クラスA:
   ...: パス
   ...: 

[2]の場合:isinstance(A、object)
Out [2]:True

クラスが古いスタイルのクラスであっても、それはのインスタンスですobject


2
正しいテストはisinstance(A(), object)、そうisinstance(A, object)ではない、そうではないと思いますか?後者では、あなたがするかどうかをテストしているクラスが Aあるobject質問がかどうかであるのに対し、インスタンスのがAありobject、右?
Eric O Lebigot 2012年

5
PS:最良のテストissubclass(HTMLParser, object)はFalseを返すのようです。
Eric O Lebigot 2012年

5

正しい方法は、「オブジェクト」から継承しない古いスタイルのクラスでは次のようになります

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

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

1
質問では、この方法はすでに述べられています。問題は、エラーメッセージが消えるのではなく、(特にこの方法で)エラーメッセージが生成された理由を理解することです。
エリックOレビゴット2014

さらに、このソリューションはA、状態を格納するクラスのインスタンスを呼び出す必要がある場合には機能しません。
tashuhka 2015年

0

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

必要に応じて、解析結果を取得しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.