チラ裏備忘録

情報整理

Python クラスの継承 super().__init()__

変数の上書き

super().__init__()は,スーパークラスのコンストラクタを実行するための命令です.
下記の例を見てみましょう.

class Parent:
    def __init__(self):
        self.test_num = 10

    def show_num(self):
        print(self.test_num)

class Child(Parent):
    def __init__(self, num):
        self.test_num = num
        super().__init__()


child1 = Child(5)
child1.show_num() # 10

Childクラスのコンストラクタ内で,self.test_numに5を代入しています.
その下でsuper().__init__()と,スーパークラスのコンストラクタを実行しています.

するとどうなるでしょうか?
このプログラムを実行すると,10が表示されます.

child1のself.test_numは5じゃないの?と思うかもしれませんが,これがsuper().__init()__の働きです.

スーパークラスのコンストラクタを見ると,同様にself.test_numに対して値を代入していますね.
つまり,self.test_num = 10という処理を行うコンストラクタをChildクラス内で実行したことで,値が上書きされたのです.
イメージとしては以下のように,Childクラス内にスーパークラスのコンストラクタ処理が埋め込まれたような感じでしょうか.

class Child(Parent):
    def __init__(self, num):
        self.test_num = num
        self.test_num = 10 # 埋め込まれ,値を上書き

勿論,super().__init__()をコメントアウトすると5が表示されます.

親クラスでのみ定義した変数も利用可能に

次は以下のような例を考えてみます.単純化のためにスーパークラスはコンストラクタ以外に関数を持たせていません.

class Parent:
    def __init__(self):
        self.parent_num = 20 # 親独自の変数をコンストラクタ内で定義する

class Child(Parent):
    def __init__(self):
        pass
        # super().__init__()
    
    def show_parent_num(self):
        print(self.parent_num)


child1 = Child()
child1.show_parent_num()

この状態でプログラムを実行すると,『AttributeError: 'Child' object has no attribute 'parent_num'』と表示され,Childオブジェクトはparent_numという変数を持っていないとエラーが表示されます.
当たり前ですね.スーパークラス内でしか定義されていない変数ですから,Child内から参照できるはずがありません(クラスの継承によって引き継がれるのはあくまで関数の処理のみ).

そこで,super().__init__()のコメントアウトを外し,passを消してみます.
すると,20が表示されます.これも先述のように埋め込まれた形で説明できますね.

class Child(Parent):
    def __init__(self):
        super().__init__()

class Child(Parent):
    def __init__(self):
        self.parent_num = 20

こうなることで,Child内のshow_parent_numメソッドから,まさに自分自身のself.parent_numを呼び出した,と自然な解釈が可能です.