はじめに
Pythonでクラスを継承してると、ついこう思ったことありませんか?
「
super()
? なんか親クラス呼ぶやつでしょ?」
実はそれ、半分正解で半分間違いです。
super()
は単に「親」を呼ぶのではなく、MRO(メソッド解決順序) という仕組みに従って「次に呼ぶべきクラス」を決めています。
この仕組みを理解していないと、多重継承やフレームワーク利用時に思わぬバグにハマることも…。
この記事では、super()
の基本からMRO、多重継承の動き、実務での使い所、そして落とし穴までをまとめます。
「なんとなく使ってる」から「正しく使いこなす」へ、一段レベルアップしましょう!
💡 super()って何者?
「親を呼ぶ関数」だと思われがちですが、実際は MROに沿って次のクラスを呼ぶバトンリレー です。
Python3 以降なら、引数なしでシンプルに書けます。
🔰 基本の使い方
class Parent:
def greet(self):
print("Hello from Parent")
class Child(Parent):
def greet(self):
print("Hello from Child")
super().greet() # ← 親クラスの greet を呼ぶ
c = Child()
c.greet()
出力:
Hello from Child
Hello from Parent
➡️ super().greet()
で親クラスの greet
メソッドを呼べていることがわかります。
🔰 Python2の場合(補足)
Python2 では、super()
を呼ぶときに 「自分のクラス」と「self」 を明示的に渡す必要がありました。
class Child(Parent):
def greet(self):
print("Hello from Child")
super(Child, self).greet() # ← クラスとインスタンスを指定
Python3 ではこれが不要になり、シンプルに super().method()
でOK。
可読性も保守性も段違いに良くなっています。
⚙️ 多重継承の正体はMROだった!
複雑そうに見える多重継承も、MROを知れば仕組みはシンプルです。
例:単純な多重継承
class A:
def greet(self):
print("Hello from A")
class B(A):
def greet(self):
print("Hello from B")
super().greet()
class C(A):
def greet(self):
print("Hello from C")
super().greet()
class D(B, C):
def greet(self):
print("Hello from D")
super().greet()
d = D()
d.greet()
出力:
Hello from D
Hello from B
Hello from C
Hello from A
➡️ 実行すると、D → B → C → A
の順で呼ばれます。
この順序は C3線形化アルゴリズム で決まっていますが、細かい説明は割愛。
今回の例で重要なのは次の3点だけ。
- 定義で
D(B, C)
と書いたのでB
がC
より優先 -
B
の中では「B が A より前」 -
C
の中では「C が A より前」
結果として D → B → C → A の順序になる、というわけです。
💡 継承関係がややこしいときは mro()
を使えば一発!
print(D.mro())
出力:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
👉 どの順番で呼ばれるか、確認できれば怖くない!
🚀 super()を使うとコードがスッキリ!
「親クラスを直呼び」しても動くけど、冗長で読みにくい…。
そんなとき super()
に置き換えるとスッキリします。
1. 直呼びコード(動くけど冗長)
class Base:
def process(self):
print("Base process")
class Logger(Base):
def process(self):
print("Logger start")
Base.process(self) # 親を直呼び
print("Logger end")
class Auth(Logger):
def process(self):
print("Auth check")
Logger.process(self) # 親を直呼び
print("Auth done")
a = Auth()
a.process()
出力:
Auth check
Logger start
Base process
Logger end
Auth done
👉 結果は正しいけど、親クラス名をべた書きしているので、継承関係を変えたら全部修正が必要。
2. superに置き換えたコード(スッキリ!)
class Base:
def process(self):
print("Base process")
class Logger(Base):
def process(self):
print("Logger start")
super().process() # superでスッキリ
print("Logger end")
class Auth(Logger):
def process(self):
print("Auth check")
super().process() # superでスッキリ
print("Auth done")
a = Auth()
a.process()
出力:
Auth check
Logger start
Base process
Logger end
Auth done
👉 動きは同じ。でも super()
にするだけで:
- 親クラス名を直接書かなくていい
- 継承関係を変えても修正不要
- 多重継承でもMROに従って安全
コードの見通しが圧倒的に良くなります。
🎯 まとめ:super()
は速くならない。でもコードは強くなる
正直、super()
を使っても処理速度が爆速になるわけではありません。
でも――
- 可読性が上がる
- 余計な記述が減る
- 継承関係を変えても壊れない
これだけで十分、実務では大きな武器になります。
「なんとなく親呼ぶやつ」と思っていた super()
は、実は “Pythonらしい継承” を支えるキーパーツ。
知っているかどうかで、コードの綺麗さと安心感はまるで違います。
👉 ぜひ自分のコードでも super()
を積極的に取り入れてみてください!