継承(Inheritance)
既存のクラスが持つ変数とメソッドを引き継いで(継承して)、新しいクラスをつくる仕組み
class Diagonal:
def __init__(self):
self.name = 'Class Diagonal'
class Straight(Diagonal):
pass
s = Straight()
print(s.name)
実行結果
Class Diagonal
実行すると、Class Diagonal
という文字が表示される。Class Straight
にはname
という変数宣言はないがDiagonalクラスで定義された変数にStraightクラスがアクセスできている。
class Straight(Diagonal)
とクラス名の隣にかっこで他のクラス名を入れることで、上の場合だとStraightクラスはDiagonalクラスを継承するという意味になる。
継承元のクラス(Diagonalクラス)のことをスーパークラス(親クラス)といい、Straightクラスはサブクラス(子クラス)になる。
オブジェクトのデータメンバーとメソッドの一覧
あるオブジェクトのデータメンバーとメソッドのリストは、dir(オブジェクト)
として取得できる。
print(dir(s))
とすると下記のように出力され、オブジェクトStraightにname
があることが確認できる。
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
メソッドの追加
子クラスで関数を追加することができる。子クラスからは、親クラスのメソッドも呼べる。
子クラスが親クラスの機能を含む。
class Diagonal:
diag = "diagonal"
def funcD(self):
print('func D')
class Straight(Diagonal): # DiagonalClassを継承
def funcS(self):
print('func S')
def diag_print(self):
print(self.diag)
s = Straight()
s.funcD()
s.funcS()
s.diag_print()
実行結果
func D
func S
diagonal
このように継承を用いると、継承元のクラスの変数とメソッドを継承先のクラスで利用できる。
→既存のクラスを修正せずに機能追加が可能になり、保守性・再利用性が向上する
また継承は、クラスの共通部分を別クラスとしてまとめる仕組みともいうことができる。
以下の2つのクラスを見てみると、プログラムの内容に共通する部分が多いことがわかる。
class Soccer_player:
def __init__(self, name):
self.name = name
def hello(self):
print("私の名前は{}です".format(self.name))
def shoot(self, field):
print("{}で点を決めた".format(field))
class Baseball_player:
def __init__(self, name):
self.name = name
def hello(self):
print("私の名前は{}です".format(self.name))
def home_run(self, field):
print("{}でホームランを打った".format(field))
継承を使うとこのコードの共通部分をまとめることができる。
class Sports_player:
def __init__(self, name):
self.name = name
def hello(self):
print("私の名前は{}です".format(self.name))
class Soccer_player(Sports_player):
def shoot(self, field):
print("{}は{}で点を決めた".format(self.name,field))
class Baseball_player(Sports_player):
def home_run(self, field):
print("{}は{}でホームランを打った".format(self.name,field))
s = Soccer_player("クリステファン・ローディ")
b = Baseball_player("バーズ")
s.hello()
s.shoot("日産スタジアム")
b.hello()
b.home_run("東京ドーム")
実行結果
私の名前はクリステファン・ローディです
クリステファン・ローディは日産スタジアムで点を決めた
私の名前はバーズです
バーズは東京ドームでホームランを打った
Soccer_playerクラスとBaseball_playerクラスはSports_playerクラスを継承している。
2つのクラスの共通部分をSports_playerクラスにまとめた上で、Sports_playerクラスを敬称している
共通部分をまとめると、以下のようなメリットがある
- プログラムの記述量が少なくなり、見通しが良くなる
- 他のスポーツ選手のクラスを定義するのが簡単になる
- 共通部分の変更が容易になる
共通部分をまとめることで、プログラムの保守性・再利用性を向上させている
オーバーライド(override)
継承では同じメソッドがあると、内容を上書きして差し替えることが可能。
class Diagonal:
def hello(self):
print('Hello Class Diagonal')
class Straight(Diagonal):
def hello(self):
print('Hello Class Straight')
s = Straight()
s.hello()
実行結果
Hello Class Straight
上のようにHello Class Straight
と表示される。自分自身の定義が先で、なかったら親を探しにいく。親にもなければさらにその上へと探しに行く。
super関数
親クラスのメソッドに、子クラスからアクセスするときに使うのが、super関数。
super().親クラスのメソッド(引数)
のように記述する。
class Diagonal:
def hello(self):
print('Hello Class Diagonal')
class Straight(Diagonal):
def hello(self):
super().hello()
print('Hello Class Straight')
s = Straight()
s.hello()
実行結果
Hello Class Diagonal
Hello Class Straight
上記の例だと、Diagonalクラスのhelloを呼び出してから、Straightクラスのhelloを呼び出している。