継承 / 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 Worker:
def __init__(self, name):
self.name = name
def greet(self):
return f"{self.name}がいます"
def __str__(self):
return f"{self.__class__.__name__}({self.name})"
class Manager(Worker):
def __init__(self, name, department):
super().__init__(name) # 親の__init__を呼ぶ
self.department = department # 子クラス固有の属性
def greet(self): # メソッドのオーバーライド
return f"{self.name}が会議に参加した!"
def report(self): # 子クラス固有のメソッド
return f"{self.name}がレポートを提出した!"
class Engineer(Worker):
def greet(self):
return f"{self.name}がコードレビューを開始した!"
m = Manager('member_a', 'dept_x')
e = Engineer('member_b')
print(m.greet()) # member_aが会議に参加した!
print(e.greet()) # member_bがコードレビューを開始した!
print(m.report()) # member_aがレポートを提出した!
print(m.department) # dept_x
# isinstance で継承関係を確認
print(isinstance(m, Manager)) # True
print(isinstance(m, Worker)) # True(Workerも継承している)
# super()でオーバーライドしつつ親も呼ぶ
class Director(Manager):
def greet(self):
base = super().greet() # Managerのgreetを呼ぶ
return f"{base}(役員)"
director = Director('member_c', 'dept_y')
print(director.greet()) # member_cが会議に参加した!(役員)
# 多重継承と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 member_aが会議に参加した! member_bがコードレビューを開始した! member_aがレポートを提出した! dept_x True True member_cが会議に参加した!(役員) 空を飛ぶ。 (<class '__main__.Duck'>, <class '__main__.Flyable'>, <class '__main__.Swimmable'>, <class 'object'>)
概要
MRO(Method Resolution Order)とはメソッドを検索する順序で、Pythonはクラスの継承ツリーをC3線形化アルゴリズムで解決します。『クラス.__mro__』で確認でき、多重継承時にどのクラスのメソッドが優先されるかを決定します。
子クラスで『__init__()』を定義する際は、基本的に親の『__init__()』をsuper()で呼ぶ必要があります。呼ばないと親クラスの初期化が行われず、親クラスのインスタンス変数が設定されないため、親クラスのメソッドを呼び出すとエラーになります。
多重継承はコードの複雑度を高めるため、可能であれば「コンポジション(合成)」パターン(継承より委譲)で代替することが推奨されます。Mixinクラス(特定の機能だけを追加するための親クラス)として使う場合は多重継承が有効です。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。