多重継承の基本理解
多重継承の定義と特性
Pythonでは、クラスが複数の親クラスから属性やメソッドを継承する多重継承をサポートしています。同名メソッドが複数の親クラスに存在する場合、どのメソッドが呼び出されるかは継承順序によって決定されます。
class FirstClass:
def display(self):
print("FirstClassの表示")
class SecondClass:
def display(self):
print("SecondClassの表示")
class Combined(FirstClass, SecondClass):
pass
instance = Combined()
instance.display() # 出力: FirstClassの表示
この例では、CombinedクラスがFirstClassとSecondClassを継承しています。displayメソッドを呼び出すと、最初に継承されたFirstClassのメソッドが実行されます。
メソッド解決順序(MRO)の仕組み
PythonはC3線形化アルゴリズムを使用してメソッド解決順序を決定します。クラスのMROは__mro__属性で確認できます。
print(Combined.__mro__)
# 出力: (<class '__main__.Combined'>, <class '__main__.FirstClass'>, <class '__main__.SecondClass'>, <class 'object'>)
特定の親クラスメソッドを呼び出す手法
クラス名を指定した直接呼び出し
親クラス名を明示的に指定することで、特定の親クラスのメソッドを呼び出すことができます。
class FirstClass:
def display(self):
print("FirstClassの表示")
class SecondClass:
def display(self):
print("SecondClassの表示")
class Combined(FirstClass, SecondClass):
def display(self):
FirstClass.display(self) # FirstClassのメソッドを呼び出し
SecondClass.display(self) # SecondClassのメソッドを呼び出し
instance = Combined()
instance.display()
# 出力:
# FirstClassの表示
# SecondClassの表示
super()関数を利用した呼び出し
super()関数を使用すると、MROに従って次のクラスのメソッドを呼び出すことができます。
class FirstClass:
def display(self):
print("FirstClassの表示")
class SecondClass:
def display(self):
print("SecondClassの表示")
class Combined(FirstClass, SecondClass):
def display(self):
super().display() # MRO順にFirstClassのdisplayを呼び出す
instance = Combined()
instance.display()
# 出力: FirstClassの表示
各親クラス内でもsuper()を使用することで、メソッドチェーンを構築できます。
class FirstClass:
def display(self):
print("FirstClassの表示")
super().display()
class SecondClass:
def display(self):
print("SecondClassの表示")
class Combined(FirstClass, SecondClass):
def display(self):
super().display()
instance = Combined()
instance.display()
# 出力:
# FirstClassの表示
# SecondClassの表示
実践的な応用例
class LivingBeing:
def make_sound(self):
print("生物の音")
class Mammal(LivingBeing):
def make_sound(self):
print("哺乳類の音")
super().make_sound()
class Avian(LivingBeing):
def make_sound(self):
print("鳥類の音")
class FlyingMammal(Mammal, Avian):
def make_sound(self):
print("飛翔哺乳類の音")
Mammal.make_sound(self)
Avian.make_sound(self)
creature = FlyingMammal()
creature.make_sound()
# 出力:
# 飛翔哺乳類の音
# 哺乳類の音
# 生物の音
# 鳥類の音
設計上の注意点とベストプラクティス
ダイヤモンド継承の回避
複数の親クラスが同じ基底クラスを継承し、子クラスがそれらの親クラスを多重継承するダイヤモンド継承は、MROの複雑化を招く可能性があります。
class Base:
def show(self):
print("Baseの表示")
class Derived1(Base):
def show(self):
print("Derived1の表示")
class Derived2(Base):
def show(self):
print("Derived2の表示")
class MultiDerived(Derived1, Derived2):
pass
obj = MultiDerived()
obj.show()
# 出力: Derived1の表示
MROの確認と理解
複雑な継承構造では、常にMROを確認してメソッド解決順序を理解することが重要です。
print(MultiDerived.__mro__)
# 出力: (<class '__main__.MultiDerived'>, <class '__main__.Derived1'>, <class '__main__.Derived2'>, <class '__main__.Base'>, <class 'object'>)
super()の適切な活用
super()を効果的に使用することで、コードの柔軟性と保守性を向上させることができます。
class Base:
def show(self):
print("Baseの表示")
class Derived1(Base):
def show(self):
print("Derived1の表示")
super().show()
class Derived2(Base):
def show(self):
print("Derived2の表示")
super().show()
class MultiDerived(Derived1, Derived2):
def show(self):
print("MultiDerivedの表示")
super().show()
obj = MultiDerived()
obj.show()
# 出力:
# MultiDerivedの表示
# Derived1の表示
# Derived2の表示
# Baseの表示
| 手法 | コード例 | 特徴 |
|---|---|---|
| クラス名指定呼び出し | FirstClass.display(self) |
特定の親クラスメソッドを直接呼び出し |
| super()利用呼び出し | super().display() |
MRO順に次のクラスのメソッドを呼び出し |
| ダイヤモンド継承回避 | 同一基底クラスからの多重派生を最小化 | MROの複雑化を防止 |
| MRO確認 | print(Class.__mro__) |
メソッド解決順序の把握 |
| super()の適応的使用 | メソッドチェーンの構築 | コードの拡張性向上 |