Pythonは複数の継承をサポートしており、親のメソッド呼び出しはメソッド解決順序(MRO - Method Resolution Order)によって管理されます。**super()**関数は、階層内のスーパークラスのメソッドを呼び出すことを可能にし、特に複雑な継承の際に便利です。
**super()**は、直接の親だけでなくMROに従ってメソッドの正しい呼び出しを保証します。
class A: def do(self): print('A') class B(A): def do(self): print('B') super().do() class C(A): def do(self): print('C') super().do() class D(B, C): def do(self): print('D') super().do() D().do() # 出力: # D # B # C # A
注意点: 各メソッドはsuper()を呼び出さなければならず、そうしないとMROが「壊れて」しまいます。また、コンストラクタ(__init__)もsuper().__init__()を呼び出す必要があります。
質問: 複数の継承の階層で、クラスの一つが自分のメソッド内でsuper()の呼び出しを「忘れた」とき、何が起こりますか?
回答: MROが破壊され、親のメソッドの一部が呼び出されなくなります。例:
class A: def show(self): print('A') class B(A): def show(self): print('B') class C(A): def show(self): print('C') super().show() class D(B, C): def show(self): print('D'); super().show() D().show() # 出力: D B # AメソッドのCおよびAは全く呼ばれない
物語
super().__init__()を呼び出すのを忘れた結果、ウィジェットの一つが適切に初期化されず、珍しいバグだけが示されました。物語
物語
複雑なミックスインの階層でオーバーライドした際に、一つのメソッドがsuper()を呼び出すのを「忘れ」ました。その結果、あるAPIエンドポイントではバリデーションが動作せず、別のものでは正常に通過しました。エラーは数週間後にMROを手動で調査するまで見つかりませんでした。