読者です 読者をやめる 読者になる 読者になる

基底クラスの__init__()について

python C#

最近必要に迫られてC#を勉強してるkk6です。

[雑記] コンストラクター内の仮想メソッド呼び出し
(C# によるプログラミング入門)
←ここの「余談: 実行順序に関して」という見出し以下のC#のコードを実行すると以下のように出力される。

Member derived
Member base
Base()
Derived()

C#では「メンバー変数初期化子 → コンストラクター初期化子 → コンストラクター本体の順」で初期化されるらしいのでこのような結果となる。

Pythonでかいてみた

class Member(object):
    def __init__(self, s):
        print "Member {0}".format(s)

class Base(object):
    
    def __init__(self):
        self.x = Member("base")
        print "Base()"

class Derived(Base):
    
    def __init__(self):
        self.x = Member("derived")
        print "Derived()"

if __name__ == '__main__':
    Derived()

出力結果:

Member derived
Derived()

おや?継承元であるBaseクラスのコンストラクタが実行されてない。これはいったいどういうことだろう?

基底クラスの__init__() メソッドは自動では実行されない

データモデル — Python 2.7ja1 documentationに書いてあった。

基底クラスが __init__() メソッドを持っている場合、導出クラスの __init__() メソッドでは、例えば BaseClass.__init__(self, [args...]) のように、必要ならば明示的に基底クラスの __init__() メソッドを呼び出して、インスタンスの基底クラスに関わる部分が正しく初期化されるようにしなければなりません。

上記を踏まえて下記のようにDerivedクラスのコンストラクタに一行追加する。

class Derived(Base):

    def __init__(self):
        self.x = Member("derived")
        Base.__init__(self) # ←明示的に呼び出す
        print "Derived()"

出力結果:

Member derived
Member base
Base()
Derived()

これでC#と同じ結果になった。

Pythonの__init__()メソッドは厳密にはコンストラクタではないというのはこういう事なのね。