クラス

INPUT · スライド

上書きして、親も呼ぶ

01 / 07

受けついだままでは合わないとき

親に書いた aisatsu は「こんにちは」と言う。でもプレミアム会員には「いつもありがとうございます」と言わせたい。

このために premium_aisatsu のような別の名前のメソッドを足すと、呼ぶ側が相手によって呼ぶ名前を変えることになってしまう。それは避けたいよね。

02 / 07

同じ名前で書き直す

子クラスに親と同じ名前のメソッドを書くと、その子ではそっちが使われる。これをオーバーライド(上書き)と呼ぶよ。

呼ぶ側は今までどおり aisatsu() と書くだけ。動きだけが差し替わるんだ。

class Kaiin:    def __init__(self, namae):        self.namae = namae    def aisatsu(self):        print(f"{self.namae}さん、こんにちは")class PremiumKaiin(Kaiin):    def aisatsu(self):        print(f"{self.namae}さん、いつもありがとうございます")p = PremiumKaiin("ゆい")p.aisatsu()

実行結果

ゆいさん、いつもありがとうございます

03 / 07

親のほうは変わらない

上書きされるのはその子から呼んだときだけ。親のメソッドは無事に残っているし、ほかの子にも影響しないよ。

Python はメソッドを呼ばれると、まず子を探して、無ければ親を見に行く。子に同じ名前があれば、親まで行かずにそこで見つかる——それだけのことなんだ。

class Kaiin:    def __init__(self, namae):        self.namae = namae    def aisatsu(self):        print(f"{self.namae}さん、こんにちは")class PremiumKaiin(Kaiin):    def aisatsu(self):        print(f"{self.namae}さん、いつもありがとうございます")k = Kaiin("はると")p = PremiumKaiin("ゆい")k.aisatsu()p.aisatsu()

実行結果

はるとさん、こんにちは
ゆいさん、いつもありがとうございます

04 / 07

super() でもとの処理も呼ぶ

上書きしたうえで、親のもとの処理も使いたいことがある。そんなときは super()(スーパー)と書くよ。

super().aisatsu() は「親のほうの aisatsu を走らせて」という意味。親のぶんをやってから、自分の分を足せるんだ。

class Kaiin:    def __init__(self, namae):        self.namae = namae    def aisatsu(self):        print(f"{self.namae}さん、こんにちは")class PremiumKaiin(Kaiin):    def aisatsu(self):        super().aisatsu()        print("いつもありがとうございます")p = PremiumKaiin("ゆい")p.aisatsu()

実行結果

ゆいさん、こんにちは
いつもありがとうございます

05 / 07

子だけ持ちものを増やす

プレミアム会員にだけ「ランク」を持たせたい。つまり __init__ を子で上書きしたい。

このとき super().__init__(namae) を先に呼ぶ。親がやることは親にまかせて、子は増えたぶんだけ書く。これが継承のいちばん定番の形だよ。

class Kaiin:    def __init__(self, namae):        self.namae = namaeclass PremiumKaiin(Kaiin):    def __init__(self, namae, rank):        super().__init__(namae)        self.rank = rankp = PremiumKaiin("ゆい", "きん")print(p.namae)print(p.rank)

実行結果

ゆい
きん

06 / 07

super() を呼び忘れると

子に __init__ を書くと、親の __init__ は自動では走らなくなる。上書きしたのだから当然だね。

super().__init__(namae) を書き忘れると、namae を入れる人がいなくなる。しかもエラーが出るのは実物を作るときではなく、使おうとしたとき。気づきにくいまちがいだよ。

class Kaiin:    def __init__(self, namae):        self.namae = namaeclass PremiumKaiin(Kaiin):    def __init__(self, namae, rank):        self.rank = rankp = PremiumKaiin("ゆい", "きん")print(p.namae)

実行結果

AttributeError: 'PremiumKaiin' object has no attribute 'namae'

07 / 07

書き分けの目安

上書きするとき、super() を使うかどうかはこう考えよう。

  • 親の処理はまるごと要らない → super() は書かない
  • 親の処理に足したい → super() を呼んでから差分を書く

__init__ はほとんどの場合「足したい」ほうなので、super().__init__(...) を書くのが定番だよ。

これでクラスの道具はひととおりそろった。次は章の総合演習だ。