多重継承ではどのように機能しますか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().__init__
? どの実行を選択するかは選択できますか?
メソッド解決順序と関係があるのはわかっています(MRO)。
ベストアンサー1
これについては、Guido自身がブログ記事でかなり詳細に説明しています。メソッド解決順序(以前の 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'>)