super()は次のエラーで失敗します:親がオブジェクトから継承しない場合、TypeError「引数1はclassobjではなく、型でなければなりません」


196

理解できないエラーが出ます。サンプルコードの何が問題なのか手掛かりはありますか?

class B:
    def meth(self, arg):
        print arg

class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

「スーパー」組み込みメソッドの助けを借りてサンプルテストコードを取得しました。

ここにエラーがあります:

Traceback (most recent call last):
  File "./test.py", line 10, in ?
    print C().meth(1)
  File "./test.py", line 8, in meth
    super(C, self).meth(arg)
TypeError: super() argument 1 must be type, not classobj

参考までに、これはpython自体のヘルプ(スーパー)です。

Help on class super in module __builtin__:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
 |


3
メス?それはプログラミング用語ですか、それとも...知っていますか?どうか明らかにしてください。
Cplusplusplus

3
@Cplusplusplus:おそらくメソッドを意味します;-)
ShadowFlame

回答:


333

問題は、クラスBが「新しいスタイルの」クラスとして宣言されていないことです。次のように変更します。

class B(object):

そしてそれは動作します。

super()そして、すべてのサブクラス/スーパークラスのものは、新しいスタイルのクラスでのみ機能します。(object)新しいスタイルのクラスであることを確認するために、クラス定義で常にそれを入力する習慣をつけることをお勧めします。

古いスタイルのクラス(「クラシック」クラスとも呼ばれます)は常にタイプclassobjです。新しいスタイルのクラスはタイプtypeです。これが、表示したエラーメッセージが表示される理由です。

TypeError: super() argument 1 must be type, not classobj

これを試してみてください:

class OldStyle:
    pass

class NewStyle(object):
    pass

print type(OldStyle)  # prints: <type 'classobj'>

print type(NewStyle) # prints <type 'type'>

Python 3.xでは、すべてのクラスが新しいスタイルであることに注意してください。古いスタイルのクラスの構文を引き続き使用できますが、新しいスタイルのクラスを取得します。したがって、Python 3.xではこの問題は発生しません。


興味深いことに、Py27ではなくPy33で実行されている同様のエラー(TypeError:classobjではなくtypeである必要があります)をスローするbottle.py(bottlepy.org)を実行しているこの正確な問題を発見しました。
ブートロード

Python 3.xでは、「古いスタイル」のクラスはなくなりました。「古いスタイル」の宣言を使用するコードは「新しいスタイル」のクラスを宣言しているため、このエラーはPython 3.xでは発生しません。
steveha 2014年

1
クラスBを編集できない場合は、クラスAを編集して、を使用しないようにする必要がありますsuper()。クラスAは「古いスタイル」のクラスで動作するように作成する必要があります。おそらく、そのための最良の方法は、クラスA自体を「古いスタイルの」クラスにすることです。もちろん、プログラム全体をPython 3.xで実行するようにアップグレードすることをお勧めします。これにより、すべてのクラスが何をしても新しいスタイルになります。そのオプションが利用可能な場合は、それが最良のオプションです。
steveha

同じ問題がありますが、私の基本クラスはのように宣言されていclass B(object):ます。@mock.patch('module.B', autospec=B)テストケースの直前を使用したため、このエラーが発生します。これを修正する方法について何か考えはありますか?
MikeyE 2018

154

また、クラスBを変更できない場合は、多重継承を使用してエラーを修正できます。

class B:
    def meth(self, arg):
        print arg

class C(B, object):
    def meth(self, arg):
        super(C, self).meth(arg)

print C().meth(1)

16
私はコメントを残さざるを得ませんでした。これは「標準」の回答として受け入れられるべきです。
workplaylifecycle 14

9
将来のGoogle社員はPython 2.6にこだわっています。これがおそらくあなたが望んでいる答えです。基本クラスを変更できない場合(たとえば、標準ライブラリクラスをサブクラス化している場合)、この独自のクラスへの変更により、super()が修正されます。
coredumperror

それは私にはうまくいきました、あなたは誰かがそれがどのように機能するか説明できますか?
subro

@subro、これにより、クラスは「新しいスタイル」のクラス(クラスオブジェクトのタイプはtype)になりますが、「古いスタイル」のクラス(クラスオブジェクトのタイプはclassobj)もサブクラス化されます。super()新しいスタイルのクラスでは機能しますが、古いスタイルのクラスでは機能しません。
MarSoft

完璧な答え!
トム

18

Pythonのバージョンが3.Xであれば問題ありません。

私はあなたのPythonバージョンが2.Xだと思います、このコードを追加するとスーパーが機能します

__metaclass__ = type

だからコードは

__metaclass__ = type
class B:
    def meth(self, arg):
        print arg
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)
print C().meth(1)

4

また、Python 2.7を使用したときに投稿された問題にも直面しました。Python 3.4で問題なく動作しています

Python 2.7で機能させるため__metaclass__ = typeに、プログラムの先頭に属性を追加し、機能しました。

__metaclass__ :古いスタイルのクラスと新しいスタイルのクラスからの移行を容易にします。

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