super()関数について
10.4 super()関数について
オーバーライドにより、サブクラス内で継承元のメソッドに別の機能を加えることができましたが、前項までの内容ではスーパークラスのメソッドの機能が継承されなくなるという問題がありました。
そこでオーバーライドしながら、スーパークラスのメソッドの機能も継承するためには、サブクラス内でスーパークラスのメソッドが使用できるsuper()関数を使用します。
10.4.1 super()関数とは
super()関数とは、スーパークラス自身を意味するものです。第4章で学習したインスタンス自身を表すselfと似たイメージを持っていただくとわかりやすいかもしれません。
このsuper()関数を使うことで、サブクラス内からもスーパークラスのメソッドにアクセスすることが可能になります。
以下にsuperキーワードを利用した基本構文を示します。
書式:super()関数の使用方法
super().スーパークラスのメソッド名()
super()の後ろにピリオド「.」とメソッド名()を記述することで、アクセスできます。これらを踏まえて一般的なsuper()関数を使った構文について以下でまとめました。
書式:super()関数の一般的な使用方法
class サブクラス名(スーパークラス名): #コンストラクタの定義 __init__(self): super().__init__() … #メソッドの再定義と継承 メソッド名(self): super().メソッド名()
凡例
10.4.2 スーパークラスのコンストラクタの引数に関する注意点
サブクラスにはスーパークラスのメソッドだけでなくコンストラクタも継承されることは既に説明しましたが、スーパークラス内のコンストラクタの引数の設定は、どのように行えば良いのでしょうか?
以下、コンストラクタ(__init__()メソッド)についてオーバーライドしなかった場合と、super関数により継承した場合に分けて説明します。
オーバーライドしなかった場合
コンストラクタについてオーバーライドしなかった場合、スーパークラスのコンストラクタがそのまま継承されます。
通常、コンストラクタの引数は、インスタンス生成時に指定した設定値がそのまま代入されましたが、サブクラスからインスタンスを生成した場合、生成時に引数に指定した設定値は、どこに代入されるのでしょうか?
図 10.4.1: コンストラクタの引数への代入のイメージ
コンストラクタをオーバーライドしなかった場合、サブクラスからインスタンスを生成すると、生成されたインストラクタの中にはスーパークラスのコンストラクタが含まれているため、生成時に指定した引数の値は、そのままスーパークラスのコンストラクタの引数に設定されます。
図 10.4.2: コンストラクタの引数への代入のイメージ
これまでの扱ってきたプログラムでは、スーパークラスの引数には初期値が設定されておりましたが、スーパークラスのコンストラクタをそのまま継承する(オーバーライドしない)場合、インスタンス生成する際に、引数に値を指定しないとエラーになるので設定し忘れないように気を付けましょう。
1. super()関数によりコンストラクタを継承した場合
続いてコンストラクタをオーバーライドしたが、super()関数によりコンストラクタを継承した場合の、スーパークラスのコンストラクタの引数の設定方法について紹介します。
コンストラクタをsuper()関数で引き継ぐ場合、super()関数でコンストラクタを呼び出したタイミングで、引数を指定します。
凡例
先ほどと同様、スーパークラス内のコンストラクタで引数に初期値が設定されていなかった場合、super()関数でスーパークラスのコンストラクタを呼び出す際に、引数を指定しないとエラーになるので気を付けましょう。
ポイント
【コンストラクタについてオーバーライドしなかった際のポイント】
- サブクラスのインスタンス生成を行うと、生成時に指定した引き数はそのままスーパークラスのコンストラクタの引数に設定される。
- スーパークラス内で初期値を設定しなかった場合、サブクラスからインスタンス生成する際、引数を指定しないとエラーになる。
【super()関数でコンストラクタを呼び出した際のポイント】
- super()関数で呼び出した際に、スーパークラスのコンストラクタの引数を指定できる。
- super()関数で呼び出した際に、スーパークラスのコンストラクタに引数を指定しないとエラーになる。
10.4.3 スーパークラスのコンストラクタやメソッドを呼ぶプログラム
サブクラスからスーパークラスのコンストラクタやメソッドの呼び出し方法について説明しましたが、ここで実際に呼び出すプログラムを確認しましょう。
ソースコードソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第10章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第10章.ipynb
class Computer: def __init__(self,name,memory): self.name = name self.memory = memory print('スーパークラスのコンストラクタ実行されました。') def osMemory(self): print('【作成されたPCの内容】') print('・os名:',self.name) print('・メモリー:',self.memory,'GB') class notePc(Computer): def __init__(self): print('サブクラスのコンストラクタ実行されました。') super().__init__('Mac','200') def osMemory(self): super().osMemory() print('サブクラスでosMemoryが実行されました。') #サブクラスからインスタンス生成 npc = notePc() #サブクラスからosMemoryを呼び出し npc.osMemory()
実行結果
サブクラスのコンストラクタ実行されました。 スーパークラスのコンストラクタ実行されました。 【作成されたPCの内容】 ・os名: Mac ・メモリー: 200 GB サブクラスでosMemoryが実行されました。
解説
22行目でnotePcクラスのインスタンス生成を行ってますが、引数は設けておりません。
npc = notePc()
クラスComputerはコンストラクタ内でname、memoryという2つの引数を設けている一方、notePcクラスはComputerのサブクラスですが、notePcクラス内でself以外の引数なしのコンストラクタを設けており、サブクラス(notePCクラス)のコンストラクタがスーパークラス(Computerクラス)のコンストラクタをオーバーライドするためです。
図 10.4.3:コンストラクタのオーバーライド
一方、notePC内のコンストラクタ内(14~16行目)で、スーパークラスのコンストラクタを呼び出してますが(super().__init__(‘Mac’,’200′))、スーパークラス(Computerクラス)のコンストラクタは2つの引数を必要とするため、呼び出す際に、2つの引数への値(‘Mac’,’200′)を指定してます。
図 10.4.4: スーパー関数によるスーパークラスのコンストラクタの呼び出し
def __init__(self,name,memory): self.name = name self.memory = memory print('スーパークラスのコンストラクタ実行されました。')
実行結果を見ると、notePcクラスのインスタンス生成(22行目)をしたタイミングで、notePC内のコンストラクタ内で実行される命令文(「サブクラスのコンストラクタ実行されました。」の出力)が先に読み込まれた上で、Computerクラス内の命令文(「スーパークラスのコンストラクタ実行されました。」の出力)が実行されていることから、notePcクラスのコンストラクタ内でComputerクラスのコンストラクタが継承されていることがわかります。
また24行目では、notePcのインスタンスを介してosMemory()メソッドが呼び出されております。
npc.osMemory()
こちらもnotePcクラスでオーバーライドしているため呼び出されるのはnotePcクラスのものになりますが、notePcクラスの当メソッド内で、super()関数を介してスーパークラス(Computerクラス)のosMemory()メソッドを呼び出しております。
def osMemory(self): super().osMemory() print('サブクラスでosMemoryが実行されました。')
そのため実行結果から、Computerクラス、notePcクラスそれぞれのosMemory()メソッドが、notePcクラスのosMemory()メソッドで実行されていることがわかります。
図 10.4.5: スーパー関数によるスーパークラスのメソッドの呼び出し
ポイント
- サブクラスの特定のメソッド内からからsuper()関数によりスーパークラスの特定のメソッドを呼び出せる。
10.4.4 super関数で呼び出したコンストラクタに任意の引数を指定するプログラム
サブクラスからスーパークラスのコンストラクタをsuper()関数のコンストラクタを呼び出す際、呼び出し先のコンストラクタの引数を指定する必要がありました。
しかしサブクラス内で引数の値を指定したら、インスタンスごとに異なる引数(インスタンス変数)を設定できません。そこでインスタンス別に、super関数()で呼び出したスーパークラスのコンストラクタに異なる引数(インスタンス変数)を設定する方法を確認していきましょう。
ソース・フォルダー: /Desktop/Python基礎講座
ファイル名: 第10章.ipynb
アクセスURL: http://localhost:8888/notebooks/Desktop/Python基礎講座/第10章.ipynb
class Computer: def __init__(self,name,memory): self.name = name self.memory = memory def osMemory(self): print('【作成されたPCの内容】') print('・os名:',self.name) print('・メモリー:',self.memory,'GB') class notePc(Computer): def __init__(self,name,memory,year): super().__init__(name,memory) self.year = year def osMemory(self): super().osMemory() print('・製造年:',self.year,'年') #サブクラスからインスタンス生成 npc = notePc('Mac','100','2019') #サブクラスからosMemoryを呼び出し npc.osMemory()
実行結果
【作成されたPCの内容】 ・os名: Mac ・メモリー: 100 GB ・製造年: 2019 年
解説
まず13~15行目でnotePcのコンストラクタを定義しており、self以外にname、memory、yearの3つの引数を設けております。
def __init__(self,name,memory): self.name = name self.memory = memory
nameとmemoryに関しては、super関数で呼び出したスーパークラスのコンストラクタの引数に値が設定され、yearはnotePc内で宣言されたインスタンス変数(self.year)に代入されるものです。
そのためyearとは別にnameとmemoryという引数を設けることで、notePcからインスタンスを生成する際に、notePc自身のインスタンス変数に加えて、スーパークラスのインスタンス変数にも独自の値を設定することができます。
つまりはsuper()関数を使ってコンストラクタを呼び出した場合でも、インスタンス別に異なるインスタンス変数を設定できるということです。
図 10.4.6: スーパー関数によるスーパークラスのコンストラクタの呼び出し
続いて22行目でnotePcクラスのインスタンス生成を行っており、引数に「’Mac’,’100′,’2019’」を指定してます。
npc = notePc('Mac','100','2019')
最初の二つの引数(Mac、100)がsuper関数()の引数に代入され、呼び出し先のComputerクラスのコンストラクタの各引数に代入されます。
図 10.4.7: サブクラス、スーパークラスのコンストラクタに任意の引数を設定
続いて24行目では、notePcのインスタンスを介してosMemory()メソッドが呼び出されております。
npc.osMemory()
super()関数を介してスーパークラス(Computerクラス)のosMemory()メソッドを呼び出しているため、notePcクラス、ComputerクラスそれぞれのosMemory()メソッドが呼び出しされます。
def osMemory(self): super().osMemory() print('・製造年:',self.year,'年')
実行結果から、Computerクラス、notePcクラスそれぞれのosMemory()メソッドが、notePcクラスのosMemory()メソッドで実行されていることがわかります。
図 10.4.8: スーパー関数によるスーパークラスのメソッドの呼び出し