ダイアモンド継承とsuper()の続きの続き
ずっと、どこかで
super() は継承元への型変換みたいな仕組みを提供してる
と思い込んでた。
これが大きな間違いのはじまり。
道理で、super()の文章を何度読んでも釈然としないわけだ。
動的な実行環境下での複数の継承の共同をサポートすることです。 この用途は Python 特有で、静的にコンパイルされる言語や、単一の継承しかサポートしない言語では見られないものです。 これは複数の基底クラスが同じメソッドを実装する “diamond diagram” を実装できるようにします。 良い設計のために、このメソッドがすべての場合に同じ形式で呼び出せるべきです。 (呼び出しの順序が実行時に決定されることや、順序がクラスの階層の変更に対応することや、その順序には実行時まで未知の兄弟クラスが含まれえることが理由です)
この文章の意味は、
super()は「適切」かつ「まんべんなく」上位クラスのメソッドを呼ぶための仕組みを一定の記述で提供する。 つまり、継承元の仕事をキッチリこなす。
ってことだ。
次の例のコードの動作でようやくわかった。
class A(object): def talk(self): print 'This is A.' class B(A): def talk(self): print 'This is B.' super(B, self).talk() class C(A): def talk(self): print 'This is C.' super(C, self).talk() class D(B, C): def talk(self): super(D, self).talk() def main(): d = D() d.talk() if __name__ == '__main__': main()
このとき、D.talk()では
super(D, self).talk()
だけを呼んでる。
その結果、
This is B. This is C. This is A.
となる。
ちゃんと継承元の talk() をまんべんなく呼び出してる。
呼び出しの重複もない。
道理で super() を説明するために、みんな __init__() で説明するわけだ。
__init__() とかは、こう動いて欲しいもん。
Python's Super is nifty, but you can't use itで説明されてる大事な話。
親クラスに super() を記述してないクラスがあると、そこでメソッドチェーンは途切れてしまう
という点は要注意。
最後に。
『特定のクラスの仕事だけしてくれ』ってときは、迷わず
C.talk(self)
でいいんだ。