ProgrammingPythonシニア開発者

Pythonにおける継承モデルとsuper()の動作について説明してください。複数の継承におけるsuper()の使用の特徴と、どのような誤りを犯す可能性があるかについても教えてください。

Hintsage AIアシスタントで面接を突破

回答。

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は全く呼ばれない

このトピックの詳細を知らないことによる実際のエラーの例。


物語

大規模なGUIコンポーネントの継承において、途中のクラスのsuper().__init__()を呼び出すのを忘れた結果、ウィジェットの一つが適切に初期化されず、珍しいバグだけが示されました。

物語

REST APIサーバーでスーパークラスに依存していたロガーは、MROに従って全てのリクエストに「ぶら下がる」必要がありました。あるクラスがロガーを直接呼び出し、super()を介さなかったため、呼び出しのチェーンが壊れ、メッセージがログに記録されなかったため、チームは原因を長い間探しました。

物語

複雑なミックスインの階層でオーバーライドした際に、一つのメソッドがsuper()を呼び出すのを「忘れ」ました。その結果、あるAPIエンドポイントではバリデーションが動作せず、別のものでは正常に通過しました。エラーは数週間後にMROを手動で調査するまで見つかりませんでした。