順番に読み進めながら学べます

クラスの継承 — 既存クラスの機能を引き継ぐ

Python のクラスの継承を解説します。class 子(親): で親の属性とメソッドを引き継ぐ書き方、メソッドの上書き(オーバーライド)、super() で親のメソッドを呼ぶ流れを図解で押さえます。

前回__add____str__ といった特殊メソッドで、自作クラスに組み込み操作を教える書き方を整理しました。今回はオブジェクト指向の重要な要素の一つである継承について解説します。

なぜ継承を使うのか

アプリを作っていると「ほとんど同じだけど、一部だけ違う」クラスを複数用意したくなる場面が出てきます。たとえば「お客様(Customer)」と「従業員(Employee)」と「管理者(Admin)」のように、nameemail を持って greeting() を返す部分は共通で、それぞれ独自の属性やメソッドだけが追加で要る、というケースです。

3 つのクラスにそれぞれ同じ name / email / greeting() を書いてもいいのですが、全く同じコードが重複 してしまい、修正が入るたびに 3 箇所を直すことになります。共通部分を親クラスにまとめ、各クラスは「親クラスを引き継ぎつつ、差分だけ書く」 ようにすればこの問題を解決できます。これが 継承(inheritance) です。

共通部分を親クラスに集約する
Person(親クラス)name / agegreeting()Employee(子クラス)継承
共通する属性・メソッド は親クラス(Person)に集めて、差分だけ を子クラス(Employee)に書く。name / greeting を毎回書き直す必要がなくなる。

親クラスを継承する — class 子(親):

継承の書き方はシンプルです。子クラスを定義するときに、クラス名のあとに丸括弧で親クラスを指定します。これで、子クラスは親クラスが持つ属性とメソッドをそのまま引き継ぐことができます。

以下は、name / age を持って自己紹介する Person クラスを親、それを継承する Employee を子クラスにした例です。Employee 側にはメソッドを 1 つも書いていませんが、親の greeting() がそのまま呼び出せている のが分かります。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hello, {self.name}")

    def say_age(self):
        print(f"{self.age} years old")


class Employee(Person):       # ← Person を継承
    pass                       # 中身は空でもよい


e = Employee("田中", 45)
e.greeting()                  # Hello, 田中   ← 親のメソッドが呼べる
e.say_age()                   # 45 years old
親が持つ機能はそのまま子で使える
Person(親クラス)
  • 属性: name / age
  • メソッド: greeting() / say_age()
  • __init__(self, name, age)
Employee(子クラス)
  • 中身は 空(pass)
  • → 親の属性・メソッドを そのまま引き継ぐ
  • Employee("田中", 45) で 親の __init__ が呼ばれる
子クラスが空でも、親が持つすべて が使える。共通の挙動を 書き直さずに 流用できるのが継承の最大の利点。

親クラス Person を作り、それを継承するだけの Employee を定義します。

class Person: を定義し、__init__(self, name, age)self.name / self.age を代入してください。

Person の中に greeting(self) を定義し、print(f"Hello, {self.name}") を実行してください。

class Employee(Person): と書いて、本体は pass だけにしてください。

e = Employee("田中", 45) を作り、e.greeting() を実行してください。

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

メソッドのオーバーライド — 同じ名前で書き換える

継承するだけだと親の振る舞いそのままですが、子クラス側で親と同じ名前のメソッドを書くと、子クラスのほうが優先的に呼ばれます。これがオーバーライド(override)です。

たとえば Employee 用の挨拶を「Hello, Employee 田中」に変えたいときは、子クラスで greeting を再定義します。Person インスタンスから呼べば親の挨拶、Employee インスタンスから呼べば子の挨拶 — というふうに、呼び出すインスタンスがどちらのクラスかによって振る舞いが切り替わります。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hello, {self.name}")


class Employee(Person):
    def greeting(self):                # ← 同じ名前で再定義 = オーバーライド
        print(f"Hello, Employee {self.name}")


p = Person("佐藤", 30)
e = Employee("田中", 45)
p.greeting()    # Hello, 佐藤
e.greeting()    # Hello, Employee 田中    ← 子クラスのほうが呼ばれる
メソッドを呼んだときの探索順
e.greeting()Employeeに greeting?あり→ 実行Personに greeting?あれば実行なければエラー①探すYesNo時
Python は まず子クラス にメソッドがあるか探し、無ければ親クラスに探しに行く。同名なら 子のほうが優先 される — これがオーバーライド。

前のコードに greeting のオーバーライドを足します。

① 前回と同じ Person クラスを作ってください(__init__greeting)。

class Employee(Person): を定義し、その中で greeting(self) を再定義して print(f"Hello, Employee {self.name}") を実行してください。

Person("佐藤", 30)Employee("田中", 45) をそれぞれ作り、両方の greeting() を呼んで結果を比べてください。

Python エディタ

コードを実行してください

super() で親クラスのメソッドを呼ぶ

オーバーライドしつつも、親の処理は活かしてその上に追加で書きたい — そんな場面では super() を使います。super().method() と書くと、今のクラスの親クラスにある同名メソッドを呼ぶ ことができます。

たとえば「親の greetingHello, 田中 を出力した上で、子の greeting で 1 行追加したい」という場合に、子の greeting の中で super().greeting() を最初に呼んでから自分の処理を書きます。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age

    def greeting(self):
        print(f"Hello, {self.name}")


class Employee(Person):
    def greeting(self):
        super().greeting()                            # ① 親の挨拶を先に出す
        print(f"I'm Employee {self.name}")            # ② 子の挨拶を続ける


Employee("田中", 45).greeting()
# Hello, 田中
# I'm Employee 田中
super().greeting() で親の処理を活かす
Employee.greeting()子の greeting本体super().greeting()親 greetingを実行残りの子の処理呼出実行
子の greeting の中で super().greeting() を呼ぶと、親の greetingそのまま実行される。self は自動で渡されるので書かなくてよい。

__init__ をオーバーライドして属性を増やす

super() がいちばん活躍するのが __init__ のオーバーライドです。子クラスで「親の属性に加えて、子だけが持つ属性を追加したい」というケース — たとえば Employee には phone_number も持たせたい、というときです。

この場合、__init__ を子クラスでも書き直す ことになりますが、親の初期化処理(self.name = name など)は super().__init__(name, age) で 1 行で済ませて、その後に追加分だけ書くのが定石です。これで name / age の代入を 2 重に書かずに済みます。

子の __init__ で親 + 子の属性をそろえる
Employee("田中", 45, "080-...")子の __init__が走るsuper().__init__(name, age)親が name / ageを代入self.phone_number= phone_number親の属性と子の属性が揃う呼出
Employee(...) を呼ぶと子の __init__ が走る → super().__init__(name, age) で親が name / age を代入 → そのあと子が phone_number を追加。親の属性 + 子の属性 が揃った状態でインスタンスが完成する。
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age  = age


class Employee(Person):
    def __init__(self, name, age, phone_number):
        super().__init__(name, age)               # ① 親の __init__ で name / age をセット
        self.phone_number = phone_number           # ② 子だけの属性を追加

    def show(self):
        print(f"{self.name} / {self.age} / {self.phone_number}")


Employee("田中", 45, "080-1111-2222").show()
# 田中 / 45 / 080-1111-2222

super().__init__(...) を呼び忘れると属性が消える

__init__ をオーバーライドしたのに super().__init__(...) を呼ばなかった 場合、親側で行われていた self.name = name などの代入が 実行されないままになります。その後で self.name を読みに行くと AttributeError になるので、__init__ を子クラスで書き直すときは 真っ先に super().__init__(...) を呼ぶようにしましょう。

Employeephone_number を追加した __init__ を書きます。

class Person: を定義し、__init__(self, name, age)self.name / self.age を代入してください。

class Employee(Person): を定義し、__init__(self, name, age, phone_number) を書いてください。先頭で super().__init__(name, age) を呼んでから self.phone_number = phone_number を代入します。

Employee の中に show(self) を定義し、print(f"{self.name} / {self.age} / {self.phone_number}") を実行してください。

Employee("田中", 45, "080-1111-2222") を作って show() を呼んでください。

Python エディタ

コードを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1次のクラス定義のうち、DogAnimal を継承する正しい書き方はどれですか?

Q2メソッドのオーバーライド に関する説明として、最も適切なものはどれですか?

Q3子クラスの __init__super().__init__(...)書き忘れた 場合、何が起きますか?