【Python】クラスの拡張とオーバーライドの仕組み
- クラスの継承とは
- メソッドのオーバーライド
- super() を使ったスーパークラスの呼び出し
- コンストラクタのオーバーライド
- 多重継承とメソッド解決順序(MRO)
- 抽象メソッドとオーバーライド
- プロパティのオーバーライド
- オーバーライドのベストプラクティス
クラスの継承とは
クラスの継承とは、既存のクラス(スーパークラス、親クラス)の機能を引き継ぎつつ、新たな機能を追加する仕組みです。
class Animal:
def speak(self):
print("何か音を出します")
class Dog(Animal):
def speak(self):
print("ワンワン!")
dog = Dog()
dog.speak() # 出力: ワンワン!
メソッドのオーバーライド
メソッドのオーバーライドとは、親クラスのメソッドを子クラスで上書きすることです。
class Parent:
def show_message(self):
print("親クラスのメッセージ")
class Child(Parent):
def show_message(self):
print("子クラスのメッセージ")
obj = Child()
obj.show_message() # 出力: 子クラスのメッセージ
super() を使ったスーパークラスの呼び出し
オーバーライドしたメソッド内で、親クラスのメソッドを呼び出したい場合は super()
を使います。
class Parent:
def greet(self):
print("こんにちは、親クラスです")
class Child(Parent):
def greet(self):
super().greet()
print("こんにちは、子クラスです")
obj = Child()
obj.greet()
# 出力:
# こんにちは、親クラスです
# こんにちは、子クラスです
コンストラクタのオーバーライド
コンストラクタ(__init__
メソッド)もオーバーライドできます。super()
を使うと、親クラスの初期化処理を呼び出せます。
class Parent:
def __init__(self, name):
self.name = name
print(f"親クラス: {self.name}")
class Child(Parent):
def __init__(self, name, age):
super().__init__(name)
self.age = age
print(f"子クラス: {self.age}歳")
obj = Child("太郎", 10)
# 出力:
# 親クラス: 太郎
# 子クラス: 10歳
多重継承とメソッド解決順序(MRO)
Pythonでは、複数の親クラスを持つ多重継承が可能です。MRO(メソッド解決順序)を理解しておくことが重要です。
class A:
def show(self):
print("Aのshow")
class B(A):
def show(self):
print("Bのshow")
class C(A):
def show(self):
print("Cのshow")
class D(B, C):
pass
obj = D()
obj.show() # 出力: Bのshow
print(D.mro()) # MROの確認
抽象メソッドとオーバーライド
抽象メソッドを定義すると、すべてのサブクラスでメソッドをオーバーライドすることが強制されます。
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
print("ワンワン!")
dog = Dog()
dog.make_sound() # 出力: ワンワン!
プロパティのオーバーライド
Pythonの@property
デコレータを使うと、プロパティをオーバーライドできます。
class Parent:
@property
def value(self):
return "親クラスの値"
class Child(Parent):
@property
def value(self):
return "子クラスの値"
obj = Child()
print(obj.value) # 出力: 子クラスの値
オーバーライドのベストプラクティス
- オーバーライドする場合、
super()
を使って親クラスの動作を適切に呼び出す。 - 不要なオーバーライドは避け、可能な限り親クラスの機能を活用する。
- 抽象クラスを使って、明示的にオーバーライドを強制することも有効。
- プロパティのオーバーライド時には
@property
を適切に使う。