web-dev-qa-db-ja.com

派生クラスでsuper()を呼び出すときに、self .__ class__を渡すことはできますか?

私は最近、(StackOverflowを介して)基本クラスのメソッドを呼び出すために呼び出す必要があることを発見しました。

super([[derived class]], self).[[base class method]]()

それは結構です、それは動作します。ただし、変更を加えると、クラス間でコピーと貼り付けを頻繁に行い、派生クラスの引数をsuper()関数に修正するのを忘れることがよくあります。

派生クラスの引数を変更することを忘れないようにしたいのですが。代わりにself.__class__ super()関数の最初の引数として?

それはうまくいくようですが、私がこれをしてはいけない理由はありますか?

47
Simon Tewsi

いいえ、あなたがすることはできません。オーバーライドされたメソッドの基本クラスを検索するには、super()呼び出しでメソッドがどのクラスに属しているかを知る必要があります。

_self.__class___(さらに良いのはtype(self))を渡すと、super()wrongメソッドを検索するための開始点であり、最終的に独自のメソッドを再度呼び出します

メソッド解決順序シーケンスを形成するクラスのリスト内のポインタとして参照してください。 type(self)を渡すと、ポインターは元の開始点ではなく、すべてのサブクラスを参照します。

次のコードは、無限再帰エラーを引き起こします。

_class Base(object):
    def method(self):
        print 'original'

class Derived(Base):
    def method(self):
        print 'derived'
        super(type(self), self).method()

class Subclass(Derived):
    def method(self):
        print 'subclass of derived'
        super(Subclass, self).method()
_

デモ:

_>>> Subclass().method()
subclass of derived
derived
derived
derived

<... *many* lines removed ...>

  File "<stdin>", line 4, in method
  File "<stdin>", line 4, in method
  File "<stdin>", line 4, in method
RuntimeError: maximum recursion depth exceeded while calling a Python object
_

type(self)Subclassであるため、_notDerivedDerived.method()になります。

この例では、SubclassのMROは_[Subclass, Derived, Base]_であり、super()はオーバーライドされたメソッドの検索を開始する場所を知る必要があります。 type(self)を使用して、Subclassから開始するように指示すると、次にDerived.method()が見つかります。

79
Martijn Pieters

self.__class__かもしれませんnotはサブクラスですが、むしろ孫以下のクラスであり、スタック破壊ループにつながります。