TL;DR
基底クラスのコンストラクタをオーバーライドするなら、スーパークラスのコンストラクタも呼び出す必要がある。なぜなら、オブジェクトがきちんと初期化されないからだ。
super().__init__()
のポイント
- 基底クラス(継承元)のコンストラクタをオーバーライドする
- コンストラクタの上書きは
super().__init__()
- メソッドの上書きは
super().メソッド名()
メソッドを上書きする場合
基底クラスのメソッドやコンストラクタを上書きするには、名前を明示することなく親クラスを参照できる super() を使う。
super([type[, object-or-type]]) - 組み込み関数 — Python 3.9.4 ドキュメント
例えば、基底クラスが持つメソッドと同名のメソッドを定義すると、そのメソッドを上書きできる。基底クラスのメソッドやコンストラクタを利用する場合、明示的に呼び出す必要がある。
# 基底クラス(継承元)
class Parent:
def __init__(self, a, b):
self.a = a
self.b = b
def w(self):
return self.b
# 継承先
class Child(Parent):
def w(self): # メソッドのオーバーライド
return super().w()
child = Child(0, 'hello')
child.w()
# 'hello'
基底クラスのコンストラクタを上書きする場合
サブクラスにおいて、コンストラクタを定義したい場合はどうすればいいのだろうか?
サブクラスで__init__
を定義すると、親の__init__
が上書きされてしまう。親の__init__
を、サブクラスで上書きすると未定義のままになり、以下のような例外が発生する。
AttributeError Traceback (most recent call last)
エラーが起こらないように、親クラスのコンストラクタをオーバーライドする場合も、__init__
の処理の最初に、スーパークラスの__init__
の呼び出しをするとよい。
class クラス名(継承元クラス):
def __init__(self, 引数):
super().__init__(引数)
処理
以下のコードは、基底クラスのコンストラクタをオーバーライドする例である。
# 基底クラス(継承元)
class A:
def __init__(self, name):
self.name = name
# 継承先
class B(A):
def __init__(self, name, mail):
super().__init__(name) # 基底クラスのコンストラクタをオーバーライド
self.mail = mail
b = B("yamada", "gmail")
b.name
# 'yamada'
super().__init__()
をつけることで、親クラスの__init__
と同じ処理を実行してくれるのである。
# 基底クラス(継承元)
class Parent:
def __init__(self, name, age):
self.name = name
self.age = age
def my_name(self):
print("名前は" + self.name + "。年齢は" + str(self.age) + "歳。")
# 継承先
class Child(Parent):
def __init__(self, name, age):
super().__init__(name, age) # 基底クラスのコンストラクタをオーバーライド
def my_hello(self):
print("こんにちは")
# インスタンス化
yamada = Child("山田", 20)
yamada.my_name()
yamada.my_hello()
# 名前は山田。年齢は20歳。
# こんにちは