classの継承
前回の投稿でクラスの基本について書きました。クラスを使うことで同じ操作を何度も書かなくて済むというメリットがありました。クラスにはまだまだ楽をするための機能があるので紹介します。
classの継承とは?
例えば、Aというクラスを作成したとします。その次に、Aに似た属性やメソッドをもつBというクラスを作成したいとします。この時、Aの情報を借りてBを作成できれば、記述するコードは少なくて済みます。これをクラスの継承といいます。
既存のクラス(上記の例ではA)を「親クラス」、新しいクラスを「子クラス」と呼びます。継承では、機能を引き継ぐだけではなく、機能を拡張(上書き・追加)することも出来ます。
具体的には、「動物」という親クラスを作成したとします。このクラスには、「歩く」、「食べる」、「鳴く」など動物に共通する機能(メソッド)が含まれます。このクラスに「羽根」という属性を追加した「鳥」という子クラスを作成すると、親クラスの機能は引き継がれるので共通機能は使用することができます。それに加え、「飛ぶ」という機能を追加することができます。
具体例
前回作成した銀行口座クラスを例にクラス継承を解説していきます。
class BankAccount:
# 初期化メソッド
def __init__(self, owner, zandaka):
self.owner = owner # 口座の所有者名
self.zandaka = zandaka # 初期残高
# 預け入れメソッド
def azukeire(self, amount):
self.zandaka += amount
print(f"{amount}円を預け入れました。")
# 引き出しメソッド
def hikidashi(self, amount):
self.zandaka -= amount
print(f"{amount}円を引き出しました。")
# 残高確認メソッド
def check_zandaka(self):
print(f"{self.owner}の口座残高: {self.zandaka}円")
コードの詳細については、前回の投稿を参照して下さい。
田中さんがba001という口座を作成し10,000円入れたとします(インスタンス作成)。
ba001 = BankAccount('Tanaka', 10000)
①機能の追加
このBankAccountクラスでは、預け入れ、引き出し、残高確認メソッドが備わっています。
BankAccountを親クラスとして、振り込み機能を追加した子クラス(BankAccount2)を作成します。
class BankAccount2(BankAccount):
def hurikomi(self, amount, account):
self.zandaka -= amount #1
print(f"{self.owner}は{account.owner}へ{amount}円を振り込みました。残高は{self.zandaka}円です。")
account.azukeire(amount) #2
print(f"{account.owner}の残高は、{account.zandaka}円です。")
子クラスをBankAccount(親クラス)を用いて定義しました。
振り込みを行うので、hurikomi()メソッドの中でBankAccount2で作成したインスタンスの残高から指定金額を差し引き(#1)、相手先(引数account)の残高にプラスする処理(#2)を記述しています。#2の処理は親クラスのazukeire()メソッドをそのまま使用しています。
実際に動かしてみましょう。
加藤さんがba002という口座を作り、50,000円入れたとします。継承しているので、インスタンスの作成は親クラスと同じです。
ba002 = BankAccount2('Kato', 50000)
ba002は親クラスのメソッドを使用できます。
ba002.hikidashi(15000)
BankAccount2で追加した振り込み機能を試してみます。現在35,000円入っている加藤さんの口座(ba002)から10,000円入っている田中さんの口座(ba001)へ20,000円振り込みます。
ba002.hurikomi(20000, ba001)
1行目は#1のprint文による出力です。ba002から20,000円が引かれました。
2行目は#2で呼び出した親クラスのazukeire()メソッド内のprint文による出力です。このメソッドは引数accountであるba001に対するメソッドなので、ba001に20,000円がプラスされています。
3行目は#2の最終行のprint文による出力です。
子クラスで作成したインスタンスでは、親クラスのメソッドも引き継がれつつ、子クラスで新たに追加したメソッドが使えることが確認できました。
逆に、ba001(親クラスで作成したインスタンス)には振り込み機能はついていないので、ba001から振り込むことはできません。
ba001.hurikomi(5000, ba002)
②オーバーライド(上書き)
子クラスの中で親クラスと同じ名前のメソッドを作成すると、機能を上書きすることができます。
azukeire()の中のprint文の出力内容を少し変えてみました。
class BankAccount3(BankAccount):
def azukeire(self, amount): #親クラスのメソッドをオーバーライド(上書き)
self.zandaka += amount
print(f"{self.owner}は{amount}円を預け入れました。残高は{self.zandaka}円です。")
ba003 = BankAccount3('Hayashi', 500)
ba003.azukeire(10000) # オーバーライドしたメソッド
親クラスのba001でazukeire()メソッドを使用してみると、
ba001.azukeire(200)
こちらは元のazukeire()メソッドで出力されます。
③属性の追加
動物クラスに「羽根」属性を加えた鳥クラスを作成するように、新たな属性を追加することができます。
親クラスで作成した時と同様に初期化メソッドを作ります。
super().__init()__を記述することで親クラスの__init__()を呼び出すことができます。あとは、追加した属性をインスタンス変数に格納すれば、追加した属性を使用することができます。
class BankAccount4(BankAccount):
def __init__(self, owner, zandaka, type):
super().__init__(owner, zandaka)
self.type = type
def describe(self):
print(f'これは{self.owner}さんの{self.type}口座です。')
属性に'type'を追加したので、インスタンスを作成する時は、selfを除いた3つの引数が必要となります。
ba004 = BankAccount4('Nakajima', 2000, '普通')
ba004.describe()
子クラスで属性を追加する場合は、上記のように初期メソッドを書きますが、機能の追加やオーバーライドの例のように属性追加が無ければ初期メソッドは書く必要ありません。
どうしてもこの辺りの説明をするときは、インスタンスやらオブジェクトやら属性……と専門用語がたくさん出てくるので分かりにくくなってしまいますね。でも、理解してしまえば楽できるので、頑張って習得しましょう!