LoginSignup
41
32

More than 3 years have passed since last update.

【Python】super()を使ってオーバーライドする理由

Last updated at Posted at 2019-12-27

本記事について

Djangoのソースコードを見ていたところ、クラスのオーバーライドにsuper()を用いているものがたくさんありました。super()とは何なのか、用いないでオーバーライドする場合と何が違うのかを整理します。

オーバーライドとは

基底クラスと同じ名前のメソッドを派生クラス内に定義することです。基底クラスのメソッドに機能を追加・変更をすることができます。

基底クラスを定義する


# 基底クラス
class Coffee(object):
    def __init__(self, color, fragrance, price, taste, elapsed_time):
        self.color = color
        self.fragrance = fragrance
        self.price = price
        self.satisfaction = ((taste + fragrance) * price) - elapsed_time

    def drink(self):
        print(f'満足度が{self.satisfaction}点のホーフィーを飲む')


coffee = Coffee('brown', 10, 200, 10, 300)
coffee.drink() # <--- 満足度が3700点のホーフィーを飲む

基底クラスを定義したので、以下にsuper()を使った場合とそうでない場合の派生クラスを作ってみます。(両者とも機能は同じ)

基底クラスをオーバーライドする(super()を使わない)

Coffeeクラスを継承し、メソッドをオーバーライドしたクラスを作ってみます。


# Coffeeを引き継いだ後、機能を拡張したい!!

class Override(Coffee):
    # 普通にオーバーライドすると基底クラスの処理が無効化されてしまうので、処理を拡張させたいなら基底クラスと同じ処理を記述する必要がある。
    def __init__(self, color, fragrance, price, taste, elapsed_time, size):
        self.color = color
        self.fragrance = fragrance
        self.price = price
        self.satisfaction = ((taste + fragrance) * price) - elapsed_time + size * 55
        self.size = size

    def size_up(self):
        self.price += 100
        self.size += 1
        print(f'サイズが{self.size}になった!代わりに価格が高くなった...')

    # 基底クラスのメソッドも、再度イチから定義しなければならない
    def drink(self):
        print(f'満足度が{self.satisfaction}点のホーフィーを飲む')
        print(f'サイズが{self.size}はちょっと多すぎたかな...')

# 実行結果 普通のオーバーライド
override = Override('brown', 10, 200, 10, 300, 10)
override.drink() # <--- 満足度が4250点のホーフィーを飲む, サイズが10はちょっと多すぎたかな..
override.size_up() # <--- サイズが11になった!代わりに価格が高くなった....

基底クラスの__init__()drink()メソッドをオーバーライドしました。
普通にオーバーライドすると基底クラスの処理が無効化されてしまうので、単純に処理を拡張させたい場合は基底クラスと同じ処理を記述する必要があり、冗長的なコードになってしまいます。

super()を使ってオーバーライドする


class SuperOverride(Coffee):
    # Super関数で基底クラスのコンストラクタを呼び出すことで、初期化のコードはもう書かなくて良い
    def __init__(self, color, fragrance, price, taste, elapsed_time, size):
        super().__init__(color, fragrance, price, taste, elapsed_time,)
        self.satisfaction = ((taste + fragrance) * price ) - elapsed_time + size * 55
        self.size = size

    def size_up(self):
        self.price += 100
        self.size += 1
        print(f'サイズが{self.size}になった!代わりに価格が高くなった...')

    # 基底クラスのメソッドは呼び出されるので、冗長性がある
    def drink(self):
        super().drink()
        print(f'サイズが{self.size}はちょっと多すぎたかな...')

# 実行結果 super()関数を使ったオーバーライド
super_override = SuperOverride('brown', 10, 200, 10, 300, 10)
super_override.drink() # <--- 満足度が4250点のホーフィーを飲む, サイズが11はちょっと多すぎたかな... 
super_override.size_up() # <--- サイズが12になった!代わりに価格が高くなった...

SuperOverrideの__init__メソッドのパラメータ(color, fragrance, price, taste, elapsed_time)に渡された値を基底(Coffee)クラスのパラメータに代入し初期化しています。super()で基底クラスのメソッドを丸々呼び出しているので、satisfactionも引き継がれています。

なお、super().drink()super(SuperOverride self).drink()と同義です。
つまり、super(自クラス, self).メソッド名の書くこともできますが、上記コードのように省略することもできます。

まとめ

以上のように、super()は基底クラスのメソッドを継承した上で処理を拡張させたい時に使うことで、記述を節約してコードを見やすくすることができます。

41
32
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
32