Python Code Notes

Information by python engineer

super関数の使い方 Python


f:id:vigilantPotato:20190608171903p:plain

クラスの継承時によく使われるsuper()関数ですが、いまいち何をしているのかがわからずに使っていたので調べてみたところ、継承した親クラスのメソッドを子クラスから呼び出すための関数とのことなので、実際にコードを書いて動きを確認してみました。

Dogクラスを継承したOwnerクラスから、Dogクラスのインスタンス変数dog_nameと、Ownerクラスのインスタンス変数owner_nameを出力するプログラムを作成して、何をしているのか見てみます。

コード

#super_test_1.py
#エラーが出ます。
class Dog():
    def __init__(self, dog_name):
        self.dog_name = dog_name + 'を飼っています。'

class Owner(Dog):
    def __init__(self, owner_name, dog_name):
        self.owner_name = owner_name + 'は'
    
    def output(self):
        print(self.owner_name + self.dog_name)

p = Owner('shinnosuke', 'shiro')
p.output()

実行結果

Traceback (most recent call last):
  File "super_test_1.py", line 14, in <module>
    p.output()
  File "super_test_1.py", line 11, in output
    print(self.owner_name + self.dog_name)
AttributeError: 'Owner' object has no attribute 'dog_name'

上記のコードでは、

AttributeError: 'Owner' object has no attribute 'dog_name'

というエラーが発生してしまっています。
Ownerクラスの引数でdog_nameを入力しているが、それだけではself.dog_nameは定義されないためです。


そこで、次のコードではOwnerクラスでself.dog_nameを定義しなおしてみます。

コード

#super_test_2.py
#エラーは出ないが、コードの重複あり。
class Dog():
    def __init__(self, dog_name):
        self.dog_name = dog_name + 'を飼っています。'

class Owner(Dog):
    def __init__(self, owner_name, dog_name):
        self.dog_name = dog_name + 'を飼っています。'
        self.owner_name = owner_name + 'は'
    
    def output(self):
        print(self.owner_name + self.dog_name)

p = Owner('shinnosuke', 'shiro')
p.output()

実行結果

shinnosukeはshiroを飼っています。

無事に想定通りの出力が得られましたが、OwnerクラスとDogクラスでコードが重複しており、美しくないしDRY(Don't Repeat Yourself)の原則に反します。また、今回のような簡単なコードならまだ良いですが、親クラスで複雑な処理をしている場合はそれをもう一度子クラスで記述するのは不具合の原因になりそうです。

そこで便利なのが、super()関数です。

次のコードでは、super()関数を用いて、子クラス側から親クラス側の__init__を実行し、コードの重複を防いでいます。

コード

#super_test_3.py
#super()関数を利用!
class Dog():
    def __init__(self, dog_name):
        self.dog_name = dog_name + 'を飼っています。'

class Owner(Dog):
    def __init__(self, owner_name, dog_name):
        super().__init__(dog_name)
        self.owner_name = owner_name + 'は'
    
    def output(self):
        print(self.owner_name + self.dog_name)

p = Owner('shinnosuke', 'shiro')
p.output()

実行結果

shinnosukeはshiroを飼っています。

想定通りの出力が得られ、コードの重複も防げました。親クラスで複雑な処理をしていても、子クラス側からsuper()関数を通して変数を渡してあげるだけで大丈夫なので、非常に便利そうです。