クラスの継承

クラスの継承

クラスの継承

 一般的にオブジェクト指向言語においては、あるクラスをひな型として部分的に機能を改造したクラスを作ることができます。これをクラスの継承 (inheritance) とよびます。ひな型となるクラスをスーパークラス(親クラス)、スーパークラスをもとにつくられたクラスをサブクラス(子クラス)といいます。今回のサンプルコードでは、以前の記事で定義した Rectanglesクラスをひな型として、いくつかのサブクラスを設計してみます。

新しいメソッドの追加

 サブクラスは class文

 class サブクラス名(スーパークラス名)

によって定義することができます。サブクラスは初期化メソッドも含めて、スーパークラスのすべてのメソッドをそのまま受け継ぎます。サブクラスのスイート(機能を記述する場所)に新しい名前のメソッドを定義すると、サブクラスから生成されたインスタンスは、スーパークラスのメソッドに加えて、新しいメソッドを使えるようになります。

# https://python.atelierkobato.com/inheritance/

# Rectanglesクラスの定義
class Rectangles:
    def __init__(self, a, b):
        self.width = a
        self.length = b

    def area(self):
        return self.width * self.length

# Rectanglesクラスを継承してRectangles_2クラスを作成
class Rectangles_2(Rectangles):
    
    # 新しいメソッドの追加
    def perimeter(self):
        return self.width * 2 + self.length * 2

# Rectangles_2クラスのインスタンスを生成
rec = Rectangles_2(5, 10)

# スーパークラスRectangleのメソッドを使用
print("面積", rec.area())

# サブクラスRectangle_2で追加されたメソッド
print("周長", rec.perimeter())
面積 50
周長 30

 上のサンプルコードではサブクラスに perimeter() という、周の長さを返すメソッドが追加されています。Rectangles_2クラスから作られたインスタンスは、もとの Rectanglesクラスのメソッドを用いて面積を計算することもできるし、Rectangles_2クラスで追加された新しいメソッドを使って周長を求めることもできます。
 

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

 サブクラスのスイートに、スーパークラスで定義されているものと同じ名前でメソッドを定義すると、そのメソッドは上書きされます。つまり、サブクラスから作られたインスタンスは、この上書きされたほうのメソッドを実装し、スーパークラスのメソッドは呼び出されません。これをメソッドのオーバーライドとよびます。以下のサンプルコードでは、Rectanglesクラスの area()メソッドを上書きして、「面積は~です」という文字列を返すように修正します。

# https://python.atelierkobato.com/inheritance/

# Rectanglesクラスの定義
class Rectangles:
    def __init__(self, a, b):
        self.width = a
        self.length = b

    def area(self):
        return self.width * self.length

# Rectanglesクラスを継承してRectangles_3クラスを作成
class Rectangles_3(Rectangles):
    #スーパークラスのarea()メソッドを上書き
    def area(self):
        return "面積は" + str(self.width * self.length) + "です。"

# Rectangles_3クラスのインスタンスを生成
rec = Rectangles_3(5, 10)

# 上書きされたメソッドを使用
print(rec.area())
面積は50です。

 

つくりながら学ぶ! PyTorchによる発展ディープラーニング

新品価格
¥3,758から
(2019/8/21 23:29時点)

super()関数によるスーパークラスの呼び出し

 初期化メソッドについても、上述のような方法でオーバーライドすることができますが、スーパークラスの設計内容に変更があったときにサブクラスの動作に不具合が生じる可能性もあります。そこで一般的には、初期化メソッドに変更を加えるときには、super()関数でスーパークラスを呼び出します。以下のサンプルコードでは、Rectanglesクラスをもとに、Squares という正方形クラスを設計し、初期化メソッドを上書きしています。

# https://python.atelierkobato.com/inheritance/

# Rectanglesクラスの定義
class Rectangles:
    def __init__(self, a, b):
        self.width = a
        self.length = b

    def area(self):
        return self.width * self.length

# Rectanglesクラスを継承してSquaresクラスを作成
class Squares(Rectangles):

    # super()関数でスーパークラスをよびだし、
    # 初期化メソッドの引数a,bにxを渡す
    def __init__(self, x):
        super().__init__(x, x)

# Squaresクラスのインスタンスを作成
sq = Squares(10)

# 正方形の面積を計算
print(sq.area())
100

 長方形は二辺の長さを指定する必要がありますが、正方形ならば一辺の長さを与えれば性質が定まります。したがって、Squaresクラスのインスタンスを作るときには、x という1つの引数だけを与えるように設計しますが、

    def __init__(self, x):
        super().__init__(x, x)

という記述によって、x をスーパークラスの引数 a, b に渡しています。つまり、a = x, b = x という代入が行われ (a, b は等しい値をもちます)、これをスーパークラスのインスタンス変数(データ属性)の self.width と self.length に渡して、area()メソッドの計算に用いるという仕組みになっています。