1. ホーム
  2. python

[解決済み] Pythonのsuper()は多重継承でどう動くのか?

2022-03-16 21:41:10

質問

私はPythonのオブジェクト指向プログラミングの初心者なのですが、以下のような問題があります。 を理解することができます。 super() 関数 (新スタイルのクラス)、特に多重継承に関して。

例えばこんなのがあったら。

class First(object):
    def __init__(self):
        print "first"

class Second(object):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        super(Third, self).__init__()
        print "that's it"

よくわからないのは Third() クラスは両方のコンストラクタ・メソッドを継承していますか?もしそうなら、どちらのメソッドが super() そしてその理由は?

また、もう一方を実行したい場合はどうすればいいのでしょうか?Pythonのメソッド解決順序に関係するのはわかるけど( MRO ).

解決方法は?

これについては、グイドー自身がブログの記事でそれなりに詳しく説明しています。 メソッド解決順序 (以前の2つの試みも含む)。

あなたの例では Third() が呼び出されます。 First.__init__ . Pythonは、クラスの親が左から右にリストアップされるように、各属性を探します。この場合、私たちが探しているのは __init__ . ですから、もしあなたが

class Third(First, Second):
    ...

Python は、まず First で、もし First がその属性を持っていない場合、その属性は Second .

この状況は、継承がパスと交差し始めると、より複雑になります。 First から継承された Second ). 詳しくは上のリンクを読んでいただきたいのですが、簡単に言うと、Pythonは各クラスが継承リスト上に現れる順番を、子クラス自身から順番に維持しようとします。

だから、例えば、あなたが持っていた場合。

class First(object):
    def __init__(self):
        print "first"

class Second(First):
    def __init__(self):
        print "second"

class Third(First):
    def __init__(self):
        print "third"

class Fourth(Second, Third):
    def __init__(self):
        super(Fourth, self).__init__()
        print "that's it"

MROは [Fourth, Second, Third, First].

ところで、Pythonは一貫したメソッド解決順序を見つけることができない場合、ユーザーを驚かせるかもしれない動作に陥るのではなく、例外を発生させます。

あいまいなMROの例。

class First(object):
    def __init__(self):
        print "first"
        
class Second(First):
    def __init__(self):
        print "second"

class Third(First, Second):
    def __init__(self):
        print "third"

すべき Third のMROは [First, Second] または [Second, First] ? 明らかな期待値はなく、Pythonはエラーを発生させます。

TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution order (MRO) for bases Second, First

上記の例では、なぜ super() を呼び出すことができますか?この例のポイントは、MROがどのように構成されるかを示すことです。それは ではなく を印刷するためのものです。 "first\nsecond\third" といった具合です。もちろん、この例で遊んでみることもできますし、そうすべきです。 super() を呼び出し、何が起こるかを見て、Pythonの継承モデルについてより深く理解することができます。しかし、ここでの私の目標は、シンプルにして、MROがどのように構築されているかを示すことです。そしてそれは、私が説明したとおりに構築されています。

>>> Fourth.__mro__
(<class '__main__.Fourth'>,
 <class '__main__.Second'>, <class '__main__.Third'>,
 <class '__main__.First'>,
 <type 'object'>)