クラスの継承は、オブジェクト指向プログラミングにおいて非常に重要なスキルです。これは、 Python では、とても簡単に行うことができます。
このページでは、クラスの継承とは何か、クラス継承の基本書式、そしてシステムの機能を拡張する上で、とても便利なメソッドオーバーライドについて、解説していきます。
ぜひ、参考にして頂ければと思います。
1. クラスの継承とは
クラスの継承とは、「新しいクラスを作る時に、既存の他のクラスからメソッドや変数を受け継ぐことができる」というものです。例えば、クラス A を継承してクラス B を作る場合、前者を「親クラス」、後者を「子クラス」といいます。
「継承」と言うと難しく聞こえますが、実際はこれだけなので、とても簡単です。
しかし、このクラス継承は、「Pythonのオブジェクト指向プログラミングの知識と書き方まとめ」で解説しているように、オブジェクト志向プログラミングにおいて、重要の要素の一つです。
なぜなら、継承を使いこなすことで、既存のシステムを拡張することが容易になりますし、またシステム全体の保守性(維持/管理のしやすさ)も大きく向上するからです。
こうしたオブジェクト指向プログラミングの利点をよく理解するためには、上のリンク先のページもよく読んでおいてくださいね。
それでは、早速、クラス継承の方法を見ていきましょう。
1.1. クラスの継承の基本書式
クラスの継承は、次の書式で行うことができます。
class 子クラス名(親クラス名):
ステートメント
実際に見てみましょう。まず、次のような親クラス Parent を作ります。
'''親クラスを作ります。'''
class Parent:
def __init__(self, a, b):
self.num = a
self.str = b
def hello(self):
print("hello")
これを継承して、子クラス Child を作るには、次のように書きます。この例では、親クラスを継承しつつ、かつ、子クラスの専用メソッド bye() を新たに定義しています。
'''子クラスを作ります。'''
class Child(Parent):
def bye(self): #子クラスで新たに定義したメソッド
print("good bye")
子クラスでは、親クラスの変数やメソッドを、そのまま使うことができます。もちろん、子クラスで新たに定義したメソッドも使うことができます。
'''これで親クラスの定義を継承した、子クラスのインスタンスを作ることができます。'''
child_obj = Child(10, "This is a string")
'''変数を確認してみましょう。'''
print(child_obj.num)
print(child_obj.str)
'''メソッドも使うことができます。'''
child_obj.hello() #親クラスから継承したメソッド
child_obj.bye() #子クラスで定義したメソッド
子クラスで変数やメソッドを追加しても、親クラスには何も影響はありません。
1.2. 別ファイル(モジュール)で定義している親クラスを継承する
親クラスが、別ファイル(モジュール)で定義されている場合は、そのモジュールをインポートしてから、子クラスを作ります。モジュールについては、「Pythonのモジュールについて抑えておくべき知識とよく使うもの一覧」で解説しています。
例えば、別モジュールの apple_class1.py で以下のように親クラスを定義しているとします。
'''Apple クラス'''
class Apple:
'''初期化メソッド(インスタンス変数の定義)'''
def __init__(self, w, c):
self.weight = w
self.color = c
'''インスタンスメソッドの定義'''
def fresh(self, days, temp):
self.freshness = days*temp
print(f"入荷してから{days}日、平均{temp}度で保管されており新鮮度は{self.freshness}です。")
ここから、このクラスを継承して、子クラスを作るには、まずモジュールをインポートします。次の例をご覧ください。
'''Apple クラスを定義しているファイル(モジュール)をインポートする'''
from apple_class1 import Apple
'''Apple クラスを継承した NewApple クラスを作ります。'''
class NewApple(Apple):
def revenue(self, price, num): #子クラスにメソッドを追加します。
self.revenue = price*num
print(f"このリンゴの価格は{price}円で{num}個売れています。売上は{self.revenue}円です。")
'''子クラスからインスタンスを作ります。'''
apple_obj = NewApple(10, "darkred")
'''メソッドを使ってみましょう。'''
apple_obj.fresh(5, 2) #親クラスから継承したメソッド
apple_obj.revenue(100, 30) #子クラスで新しく定義したメソッド
この方法でも、親クラスで定義されている変数やメソッド、子クラスで新たに定義した変数やメソッドを、問題なく使うことができます。子クラスで、新たに定義した変数やメソッドは、親クラスには影響しません。
2. メソッドのオーバーライド
子クラスでは、親クラスのメソッドを継承して使うことができます。しかし、時に、そのメソッドを書き換えたい場合があります。そのような場合、親クラスのメソッドを書き換えるのではなく、子クラスで、同じ名前のメソッドを定義することで、上書きすることができます。
これを、メソッドの「オーバーライド(上書き)」と言います。
- 初期化メソッド
- インスタンスメソッド
のどちらでもオーバーライドすることができます。
なお、子クラスでメソッドをオーバーライドしても、親クラスには影響はありませんので、覚えておきましょう。
それでは、例を見ていきましょう。
2.1. 初期化メソッドのオーバーライド
まずは、初期化メソッドのオーバーライドを見ていきたいと思います。以下の2つの方法があります。
- 親クラスの初期化メソッドを全て上書きする方法
- 親クラスの初期化メソッドを引き継いだ上で、新たなインスタンス変数を追加する方法
それぞれ確認していきましょう。
親クラスの初期化メソッドを全て上書きする
親クラスを継承する時に、子クラスで新たに、 __init__ で始まる初期化メソッドを書くことで、上書きすることができます。
次のコードをご覧ください。
'''親クラスを作ります。'''
class Parent():
def __init__(self, name, age): #初期化メソッド
self.name = name
self.age = age
'''子クラスを作ります。'''
class Child(Parent):
def __init__(self, grade, age): #親クラスの初期化メソッドをオーバーライドしています
self.grade = grade
self.age = age
実際に確認してみましょう。
'''子クラスでは初期化メソッドがオーバーライドされています。'''
child = Child("小学二年生", 8)
print(child.parent) #子クラスの変数 parent を出力します。
print(child.age) #子クラスの変数 age を出力します。
'''親クラスに変化はありません。'''
parent = Parent("山田", 35)
print(parent.name) #親クラスの変数 name を出力します。
print(parent.age) #親クラスの変数 age を出力します。
初期化メソッドがオーバーライドされて、新しいものになっていますね。子クラスでオーバーライドしても、親クラスの初期化メソッドには変化がないこともご確認ください。
親クラスの初期化メソッドを引き継いで、さらに新しい変数を追加する
初期化メソッドは、親クラスのものを引き継いだ上で、そこに新しいインスタンス変数を追加することもできます。
その場合は、次のコードのように、子クラスの初期化メソッドブロックの最初に、「super().__init__(変数1, 変数2)」と書き、その下に、追加したいインスタンス変数を追加で書いていきます。
'''親クラスを作ります。インスタンス変数に初期値を設定します。'''
class Parent():
def __init__(self, name, age): #初期化メソッド
self.name = name
self.age = age
'''子クラスを作ります。'''
class Child2(Parent):
'''親クラスの変数も含めて初期化メソッドをオーバーライドします。'''
def __init__(self, name, age, grade, score): #引数に親クラスの変数を先に含める。
super().__init__(name, age) #親クラスの初期化メソッドを呼び出す
self.grade = grade
self.score = score
'''確認して見ましょう。'''
child2 = Child2("山田", 8, "小学二年生", 5)
print(child2.name)
print(child2.age)
print(child2.grade)
print(child2.score)
しっかり、確認しておきましょう。
2.2. メソッドオーバーライド
次に、メソッドのオーバーライドを確認したいと思います。メソッドのオーバーライドは、子クラスの中で、親クラスのメソッドと同じ名前で新たに定義することで行うことができます。
次のコードをご覧ください。
'''親クラス'''
class Greet():
def hello(self):
print("hello")
def bye(self):
print("bye")
'''子クラスを作ります。'''
class GreetChild(Greet):
'''親クラスのメソッドをオーバーライドします。'''
def hello(self, name):
print(f"hello, {name}")
'''子クラスでオーバーライドしたメソッドを使ってみましょう。'''
obj_child = GreetChild()
obj_child.hello("Mike")
'''親クラスのメソッドに変更は影響しません。'''
obj_parent = Greet()
obj_parent.hello()
親クラスで、hello() メソッドを定義しています。それを継承した子クラスを作り、その中で hello() メソッドをオーバーライドしています。もちろん、この場合も、親クラスのメソッドには、何も影響はありません。
3. まとめ
いかがだったでしょうか。
ここまで学習を進めて頂いた方なら、クラス継承の概念や方法は、特に難しくは感じないと思います。オブジェクト指向プログラミングにおいては、頻繁に使うものですので、ぜひ使いこなしていきましょう。
コメント