継承 / super() / 多重継承
| 対応: | Python 2(2000) |
|---|
Pythonでは『class 子クラス(親クラス)』という構文でクラスを継承します。子クラスは親クラスのメソッドとプロパティを引き継ぎ、必要に応じてオーバーライド(上書き)できます。『super()』は親クラスのメソッドを呼び出すために使います。Pythonは多重継承をサポートしており、複数の親クラスを持つクラスを定義できますが、設計が複雑になるため注意が必要です。
構文
# 継承
class 子クラス(親クラス):
def __init__(self, ...):
super().__init__(...) # 親の__init__を呼び出す
# メソッドのオーバーライド
def メソッド(self):
super().メソッド() # 親のメソッドも呼ぶ場合
# 追加の処理
# 多重継承
class 子クラス(親1, 親2):
pass
構文・関数一覧
| 構文・関数 | 概要 |
|---|---|
| class 子(親) | 親クラスを継承した子クラスを定義する。 |
| super() | 親クラス(またはMROの次のクラス)を参照するオブジェクトを返す。 |
| super().__init__() | 親クラスの初期化メソッドを呼び出す。 |
| class 子(親1, 親2) | 複数の親クラスを持つ多重継承のクラスを定義する。 |
| クラス.__mro__ | MRO(メソッド解決順序)をタプルで返す属性。 |
サンプルコード
sample_inheritance_super.py
# 基本的な継承
class Fighter:
def __init__(self, name):
self.name = name
def battle(self):
return f"{self.name}がいます"
def __str__(self):
return f"{self.__class__.__name__}({self.name})"
class Yakuza(Fighter):
def __init__(self, name, family):
super().__init__(name) # 親の__init__を呼ぶ
self.family = family # 子クラス固有の属性
def battle(self): # メソッドのオーバーライド
return f"{self.name}が襲いかかってきた!"
def intimidate(self): # 子クラス固有のメソッド
return f"{self.name}がダウン!"
class Freelancer(Fighter):
def battle(self):
return f"{self.name}が堂島の龍スタイルで応戦!"
y = Yakuza('嶋野太', '嶋野組')
f = Freelancer('桐生一馬')
print(y.battle()) # 嶋野太が襲いかかってきた!
print(f.battle()) # 桐生一馬が堂島の龍スタイルで応戦!
print(y.intimidate()) # 嶋野太がダウン!
print(y.family) # 嶋野組
# isinstance で継承関係を確認
print(isinstance(y, Yakuza)) # True
print(isinstance(y, Fighter)) # True(Fighterも継承している)
# super()でオーバーライドしつつ親も呼ぶ
class BossYakuza(Yakuza):
def battle(self):
base = super().battle() # Yakuzaのbattleを呼ぶ
return f"{base}(ボス)"
boss = BossYakuza('林弘', '近江連合')
print(boss.battle()) # 林弘が襲いかかってきた!(ボス)
# 多重継承とMRO(C3線形化アルゴリズム)
class Flyable:
def move(self):
return "やりまんなぁ。"
class Swimmable:
def move(self):
return "ワレほどの男、こんなところで殺しとぅないんですわ。"
class Duck(Flyable, Swimmable):
pass
duck = Duck()
print(duck.move()) # やりまんなぁ。(Flyableが先に解決される)
print(Duck.__mro__) # MROの順序を確認
# (<class 'Duck'>, <class 'Flyable'>, <class 'Swimmable'>, <class 'object'>)
python3 inheritance_super.py 嶋野太が襲いかかってきた! 桐生一馬が堂島の龍スタイルで応戦! 嶋野太がダウン! 嶋野組 True True 林弘が襲いかかってきた!(ボス) やりまんなぁ。 (<class '__main__.Duck'>, <class '__main__.Flyable'>, <class '__main__.Swimmable'>, <class 'object'>)
概要
MRO(Method Resolution Order)とはメソッドを検索する順序で、Pythonはクラスの継承ツリーをC3線形化アルゴリズムで解決します。『クラス.__mro__』で確認でき、多重継承時にどのクラスのメソッドが優先されるかを決定します。
子クラスで『__init__()』を定義する際は、基本的に親の『__init__()』をsuper()で呼ぶ必要があります。呼ばないと親クラスの初期化が行われず、親クラスのインスタンス変数が設定されないため、親クラスのメソッドを呼び出すとエラーになります。
多重継承はコードの複雑度を高めるため、可能であれば「コンポジション(合成)」パターン(継承より委譲)で代替することが推奨されます。Mixinクラス(特定の機能だけを追加するための親クラス)として使う場合は多重継承が有効です。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。