Python の super() は多重継承でどのように機能しますか? 質問する

Python の super() は多重継承でどのように機能しますか? 質問する

多重継承ではどのように機能しますか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"

のどの親メソッドを参照しますThirdsuper().__init__? どの実行を選択するかは選択できますか?

メソッド解決順序と関係があるのはわかっています(MRO)。

ベストアンサー1

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

この例では、Third()は を呼び出しますFirst.__init__。Python は、クラスの親の各属性を左から右にリストされている順に探します。この場合、 を探します__init__。したがって、次のように定義すると、

class Third(First, Second):
    ...

Python は を調べることから始めFirstFirstに 属性がない場合には を調べます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'>)

おすすめ記事