Python のクラスの継承

オブジェクト指向言語では、あるクラスを元にして、同じような構造を持ちつつ機能を拡張した別のクラスを定義することができます。

そのような状況をクラスを継承して派生クラスを定義すると言い、元となるクラスは基底クラスと呼ばれます。

ここでは Python のクラスの継承についてご説明します。

Python でクラスを継承して派生クラスを定義する

Python でクラスを継承して派生クラスを定義するには、クラスを定義する時に class 派生クラス名(基底クラス名) のようにします。

また、派生クラスの __init__() メソッド内で、基底クラスの __init__() メソッドを呼ぶには super() を使って、次のようにします。

class DerivedClassName(ParentClassName):
    def __init__(self, parameter1, parameter2, .....):
        super().__init__(self, parameter1, parameter2, ...)

では、実際に Python でクラスを継承して、派生クラスを定義して使ってみましょう。

次のような Person クラスがあります。

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

    def say_hello(self):
        print(f"Hello, I'm {self.name}!")

この Person クラスを継承した Employee という派生クラスを作ります。


Employee クラスでは Person クラスが持つ name(名前)、age(年齢)に加えて、department(部署)というクラス変数を追加してみましょう。

Employee クラスの __init__() の引数には self, name, age, department を指定し、基底クラスの super().__init__() には name と age のみを渡します。

そして、self.department に department に渡された値を代入します。

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

    def say_hello(self):
        print(f"Hello, I'm {self.name}!")


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


emp1 = Employee("Ryota", 20, "Sales")

print(emp1.name)
print(emp1.age)
print(emp1.department)
emp1.say_hello()

実行結果は次のようになります。

Ryota
20
Sales
Hello, I'm Ryota!

department に加え、Person のクラスから継承した name、age 変数や say_hello() メソッドが利用できていますね。

派生クラスにメソッドを追加する

派生クラスの Employee にメソッドを追加してみましょう。

社員の有給休暇の日数を保持する __paid_vacation_days という名前のクラス変数を使って初期値を 20 日に設定しておきます。

変数名のはじまりにアンダースコアを二個つけるのは、この変数がクラス外から直接アクセスされるべき値ではないことを示し、できるだけクラス外から直接変更されるのを防ぐためです。詳しくはこちらをご覧ください。 Python クラスのプライベート変数

そして、有給休暇を使う日数を渡して、有給休暇の日数が残っている場合は渡した日数を減らして残日数を表示、残っていなければ有給休暇の日数が足りないことを表示するような use_paid_vacation_days() メソッドを追加し、使ってみましょう。

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

    def say_hello(self):
        print(f"Hello, I'm {self.name}!")


class Employee(Person):
    def __init__(self, name, age, department):
        super().__init__(name, age)
        self.department = department
        self.__paid_vacation_days = 20

    def use_paid_vacation_days(self, days):
        if self.__paid_vacation_days >= days:
            self.__paid_vacation_days -= days
            print(f"有給休暇の残日数は {self.__paid_vacation_days} 日です。")
        else:
            print(f"有給休暇の日数が足りません。")


emp1 = Employee("Ryota", 20, "Sales")

emp1.use_paid_vacation_days(3)
emp1.use_paid_vacation_days(20)

実行結果は次のようになります。

有給休暇の残日数は 17 日です。
有給休暇の日数が足りません。

1 回目は 20 日から引数で渡した 3 を引いて、「有給休暇の残日数は 17 日です。」と出力されましたが、2 回目はもう 17 日しか残っていないのに 20 日分使おうとしたので、「有給休暇の日数が足りません。」と出力されています。


基底クラスのメソッドをオーバーライドする

基底クラスのメソッドが派生クラスでやりたいことに合わない場合は、基底クラスのメソッドをオーバーライドすることができます。

オーバーライドしたい時は派生クラスの中で同じ名前でクラスメソッドを定義します。

そうすると、その名前のメソッドが実行された時に、基底クラスのメソッドではなく、派生クラスのメソッドが実行されます。


例えば、基底クラスの say_hello() メソッドをオーバーライドしたい時は次のようにします。

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

    def say_hello(self):
        print(f"Hello, I'm {self.name}!")


class Employee(Person):
    def __init__(self, name, age, department):
        super().__init__(name, age)
        self.department = department
        self.__paid_vacation_days = 20

    def use_paid_vacation_days(self, days):
        if self.__paid_vacation_days >= days:
            self.__paid_vacation_days -= days
            print(f"有給休暇の残日数は {self.__paid_vacation_days} 日です。")
        else:
            print(f"有給休暇の日数が足りません。")

    def say_hello(self):
        print(f"Hello, I'm {self.name}. I work in the {self.department.lower()} department.")


emp1 = Employee("Ryota", 20, "Sales")
emp1.say_hello()

実行結果は次のようになり、派生クラスの say_hello() メソッドが実行されていますね。

Hello, I'm Ryota. I work in the sales department.

以上、Python のクラスの継承についてご説明しました。

© 2024 やさしい Python 入門