基礎

Pythonの継承|クラスを拡張して再利用する方法

継承は、既存のクラス(親クラス)の機能を引き継いで新しいクラス(子クラス)を作る仕組みです。共通の処理を親クラスにまとめ、子クラスで独自の機能を追加・変更することで、コードの重複を減らし、保守性を高められます。

この記事では、継承の基本から、メソッドのオーバーライド、super()の使い方、多重継承まで詳しく解説します。

基本的な使い方

子クラスの定義時に、括弧の中に親クラスを指定します。

Python
# 親クラス
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name}が鳴きます")
    
    def info(self):
        print(f"動物: {self.name}")

# 子クラス
class Dog(Animal):
    def fetch(self):
        print(f"{self.name}がボールを取ってきます")

class Cat(Animal):
    def purr(self):
        print(f"{self.name}がゴロゴロ言います")

# 子クラスは親クラスのメソッドを使える
dog = Dog("ポチ")
dog.info()     # 親のメソッド
dog.speak()    # 親のメソッド
dog.fetch()    # 子の独自メソッド

cat = Cat("ミケ")
cat.info()
cat.purr()
実行結果
動物: ポチ
ポチが鳴きます
ポチがボールを取ってきます
動物: ミケ
ミケがゴロゴロ言います

メソッドのオーバーライド

子クラスで親クラスと同名のメソッドを定義すると、親のメソッドを上書き(オーバーライド)できます。

Python
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name}が鳴きます")

class Dog(Animal):
    def speak(self):  # オーバーライド
        print(f"{self.name}: ワンワン!")

class Cat(Animal):
    def speak(self):  # オーバーライド
        print(f"{self.name}: ニャー!")

animals = [Dog("ポチ"), Cat("ミケ"), Dog("シロ")]
for animal in animals:
    animal.speak()  # 各クラスのspeakが呼ばれる
実行結果
ポチ: ワンワン!
ミケ: ニャー!
シロ: ワンワン!

このように、同じメソッド呼び出しでクラスごとに異なる動作をすることをポリモーフィズム(多態性)と呼びます。

super()で親クラスを呼び出す

super()を使うと、子クラスから親クラスのメソッドを呼び出せます。

Python
class Employee:
    def __init__(self, name, department):
        self.name = name
        self.department = department
    
    def info(self):
        return f"{self.name} ({self.department})"

class Manager(Employee):
    def __init__(self, name, department, team_size):
        super().__init__(name, department)  # 親の__init__を呼ぶ
        self.team_size = team_size
    
    def info(self):
        base = super().info()  # 親のinfoを呼ぶ
        return f"{base} - チーム: {self.team_size}名"

emp = Employee("太郎", "開発部")
mgr = Manager("花子", "企画部", 8)

print(emp.info())
print(mgr.info())
実行結果
太郎 (開発部)
花子 (企画部) - チーム: 8名

isinstance()とissubclass()

Python
class Animal:
    pass

class Dog(Animal):
    pass

dog = Dog()

# isinstance(): インスタンスの型チェック
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Animal))  # True(親クラスもTrue)

# issubclass(): クラスの継承関係チェック
print(issubclass(Dog, Animal))  # True
print(issubclass(Animal, Dog))  # False
実行結果
True
True
True
False
継承の設計指針

継承は「is-a関係」(犬は動物である)が成り立つ場合に使いましょう。「has-a関係」(車はエンジンを持つ)の場合は、継承ではなくコンポジション(属性として持つ)が適切です。深すぎる継承階層は避け、2〜3階層に留めるのがベストプラクティスです。

実践的な使い方

Python
# 図形クラスの階層
class Shape:
    def area(self):
        raise NotImplementedError("サブクラスでarea()を実装してください")
    
    def describe(self):
        print(f"{self.__class__.__name__}: 面積 = {self.area():.2f}")

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14159 * self.radius ** 2

shapes = [Rectangle(5, 3), Circle(4), Rectangle(10, 2)]
for shape in shapes:
    shape.describe()
実行結果
Rectangle: 面積 = 15.00
Circle: 面積 = 50.27
Rectangle: 面積 = 20.00
多重継承は慎重に

Pythonは多重継承をサポートしていますが、複雑になりやすく「ダイヤモンド問題」が発生する可能性があります。多重継承を使う場合はMRO(メソッド解決順序)を理解し、可能であればミックスインパターンを使いましょう。

まとめ

  • 継承で親クラスの機能を子クラスに引き継げる
  • オーバーライドで親のメソッドを子クラスで上書きできる
  • super()で親クラスのメソッドを呼び出せる
  • isinstance()で型チェック、issubclass()で継承関係を確認
  • 継承は「is-a関係」が成り立つ場合に使う