Python がこの特定の MRO アルゴリズムを選択した理由を知りたい場合は、メーリング リストのアーカイブに議論があり、 The Python 2.3 Method Resolution Orderに簡単に要約されています。
しかし、実際には、次のようになります。Python 2.2 のメソッド解決は、多重継承を処理するときに壊れていました。それを修正するために最初に提案されたのは、Dylan から C3 アルゴリズムを借りることでした。そのため、Python は C3 を使用します。
他のアルゴリズムに対する C3 の一般的な利点 (および欠点) に関心がある場合は…
BrenBarn と florquake の回答は、この質問の基本を示しています。Python の super() はスーパーと見なされます! レイモンド ヘッティンガーのブログからは、同じ趣旨のより長く、より詳細な議論があり、間違いなく読む価値があります。
A Monotonic Superclass Linearlization for Dylanは、設計を説明する元の論文です。もちろん、Dylan は Python とは非常に異なる言語であり、これは学術論文ですが、理論的根拠は依然として非常に優れています。
最後に、The Python 2.3 Method Resolution Order (上記でリンクされた同じドキュメント) には、利点に関するいくつかの議論があります。
さらに先に進むには、代替案について、またそれらがどのように Python に適しているか、または適切でないかについて、多くを学ぶ必要があります。または、SO についてさらに詳しい情報が必要な場合は、より具体的な質問をする必要があります。
最後に、「方法」の質問をしている場合:
を呼び出すとD().test()
、明らかにB
のtest
メソッドで定義したコードが呼び出されます。そしてB.__mro__
です(__main__.B, __main__.A, object)
。では、どうすれば の代わりにのメソッドをsuper(B, self).test()
呼び出すことができるでしょうか?C
test
A
ここで重要なのは、MRO が の型に基づいており、メソッドが定義さself
れた型に基づいていないことです。関数の内部に入ると、 ではなくであることがわかります。B
test
print(type(self))
test
D
B
したがって、super(B, self)
実際にself.__class__.__mro__
(この場合はD.__mro__
) を取得し、リスト内で検索B
して、その次のものを返します。かなり簡単です。
しかし、それは MRO がどのように機能するかを説明するものではなく、MRO が何をするかを説明するだけです。からメソッドをD().test()
呼び出すにはどうすればよいですか?B
self
D
まず、 と は同じ関数ではないことに注意しD().test
てD.test
くださいB.test
。これらはまったく関数ではないためです。それらはメソッドです。(ここでは Python 2.x を想定しています。3.x では少し異なり、主に単純です。)
im_func
メソッドは、基本的に、、、im_class
およびim_self
メンバを持つオブジェクトです。メソッドを呼び出すときは、最初に追加の引数として詰め込まれた(そうでない場合)im_func
を使用して、その を呼び出すだけです。im_self
None
したがって、3 つの例はすべて同じ を持ちます。im_func
これは、実際には内部で定義した関数ですB
。しかし、最初の 2 つはforではD
なく、最初のインスタンスもforの代わりにインスタンスを持っています。そのため、それを呼び出すと、インスタンスが として渡されます。B
im_class
D
None
im_self
D
self
それで、どのようにしてそれと にD().test
なりim_self
ますim_class
か?それはどこで作成されますか?それが楽しい部分です。完全な説明については、Descriptor HowTo Guideをお読みください。
を記述するたびにfoo.bar
、実際に起こることは、次のgetattr(foo, 'bar')
ようなことを行う への呼び出しと同等です (インスタンス属性、__getattr__
、__getattribute__
、スロット、ビルトインなどを無視します)。
def getattr(obj, name):
for cls in obj.__class__.__mro__:
try:
desc = cls.__dict__[name]
except KeyError:
pass
else:
return desc.get(obj.__class__, obj)
最後にそれ.get()
が魔法のビットです。関数 (たとえば )を見ると、実際にメソッドB.test.im_func
があることがわかります。そしてそれが行うことは、それ自体、クラス、およびオブジェクトとしてget
バインドされたメソッドを作成することです。im_func
im_class
obj.__class__
im_self
obj