クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

継承とポリモーフィズム

このレッスンのあとで: 継承でコードを使い回し、ポリモーフィズムで同じ呼び出しを種類ごとに変えることができる。

60分のレッスンコマンド6件毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

継承とポリモーフィズム

継承とは、既にあるクラスの属性とメソッドを受け継いで、新しいクラスを作る仕組みです。ポリモーフィズムとは、同じ呼び出しが、オブジェクトの種類によって違う動きをすることです。

2つを使うと、種類が増えても、呼ぶ側のコードを書き直さずに済みます。

このレッスンのゴール

メモ

継承でコードを使い回し、ポリモーフィズムで同じ呼び出しを種類ごとに変えることができる。

キーワード

ことばいみれい
継承親のクラスの中身を、子のクラスが受け継ぐことclass ChildTicket(Ticket)
親クラスと子クラス受け継がれる側が親、受け継ぐ側が子。サブクラスとも呼ぶ
オーバーライド親のメソッドを、子が同じ名前で書き直すこと
super()子から、親のメソッドを呼ぶ書き方
ポリモーフィズム同じ呼び出しが、種類によって違う動きをすること
is-a 関係「子は親の一種だ」と言える関係

学生が入力するセルは、このプレビューでは空白です。

子クラスは親の中身を受け継ぐ

切符のクラス Ticket に、運賃を返す fare を書いたとします。子ども用の切符も、同じ作りです。

class ChildTicket(Ticket): と書くと、ChildTicket は Ticket の属性とメソッドをすべて受け継ぎます。違う所だけを書けば足ります。

子クラスで fare だけを置き換える

コード: python
class Ticket:
    def __init__(self, base_yen):
        self.base_yen = base_yen

    def fare(self):
        return self.base_yen


# Ticket のすべてを受け継ぎ、fare だけを置き換えます。
class ChildTicket(Ticket):
    def fare(self):
        return self.base_yen // 2


print(Ticket(600).fare())
print(ChildTicket(600).fare())
# ChildTicket(800) に変えて、もう一度実行しましょう。

super() で親の計算を使う

子が親のメソッドを置き換えるとき、親の計算を残したいことがあります。そのときは super() で、親のメソッドを呼びます。

下の例では、親の運賃に200円を足しています。親の計算を書き写さないので、親を直せば子も直ります。

親の運賃に200円を足す

コード: python
class Ticket:
    def __init__(self, base_yen):
        self.base_yen = base_yen

    def fare(self):
        return self.base_yen


class NightTicket(Ticket):
    # 親の計算を使ってから、200円を足します。
    def fare(self):
        return super().fare() + 200


print(NightTicket(600).fare())
# 200 を 300 に変えて、もう一度実行しましょう。

呼ぶ側は種類を調べなくてよい

切符を全部集めて合計するコードを考えます。大人用か子ども用かを、if で調べる必要はありません。

どの切符にも fare() と呼ぶだけで、それぞれの運賃が返ります。これがポリモーフィズムです。新しい種類を足しても、この合計の関数は変わりません。

種類を調べずに合計する

コード: python
class Ticket:
    def __init__(self, base_yen):
        self.base_yen = base_yen

    def fare(self):
        return self.base_yen


class ChildTicket(Ticket):
    def fare(self):
        return self.base_yen // 2


# 呼ぶ側は、どの種類の切符かを調べません。
def total_fare(tickets):
    total = 0
    for ticket in tickets:
        total = total + ticket.fare()
    return total


print(total_fare([Ticket(500), ChildTicket(500), ChildTicket(500)]))

例: 3種類の切符の運賃

切符基本の運賃fare() の答えどう決まるか
Ticket600円600円親のまま
ChildTicket600円300円半額に置き換え
SeniorTicket600円480円親の運賃の80%
3枚の合計1380円どの切符にも fare() と呼ぶだけ

学生が入力するセルは、このプレビューでは空白です。

ラボで3種類の切符を動かす

ラボの端末で、切符のクラスと、合計を出すファイルを作ります。6つの Run を、上から順に押してください。

表の運賃が、本当にその通りに出るかを確かめます。

作業用のフォルダを作る

コマンド
mkdir -p ~/oop/inheritance

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

そのフォルダへ移る

コマンド
cd ~/oop/inheritance

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

切符のクラスを書く

コマンド
printf 'class Ticket:\n    def __init__(self, base_yen):\n        self.base_yen = base_yen\n\n    def fare(self):\n        return self.base_yen\n\n\nclass ChildTicket(Ticket):\n    def fare(self):\n        return self.base_yen // 2\n\n\nclass SeniorTicket(Ticket):\n    def fare(self):\n        return super().fare() * 80 // 100\n' > fares.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

合計を出すファイルを書く

コマンド
printf 'from fares import Ticket, ChildTicket, SeniorTicket\n\ntickets = [Ticket(600), ChildTicket(600), SeniorTicket(600)]\ntotal = 0\nfor t in tickets:\n    print(type(t).__name__, t.fare())\n    total = total + t.fare()\nprint("total", total)\n' > trip.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

動かして運賃を見る

コマンド
python3 trip.py

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

出力は表と同じになる

出力は、Ticket 600、ChildTicket 300、SeniorTicket 480、total 1380 の4行です。

ループの中に if はありません。種類ごとの違いは、クラスの中に入っています。

子は親の一種か調べる

コマンド
python3 -c "from fares import Ticket, ChildTicket; print(isinstance(ChildTicket(600), Ticket), isinstance(Ticket(600), ChildTicket))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

子は親の一種で、逆は成り立たない

出力は True False です。子ども用の切符は、切符の一種です。しかし、切符が子ども用の切符とは限りません。

「子は親の一種だ」と言えるときだけ、継承は正しい形です。これを is-a 関係と呼びます。

よくある間違い

注意

「コードを使い回せるなら、とにかく継承すればよい」と考える人が多くいます。それは間違いです。子が親の一種と言えないのに継承すると、親の変更が思わぬ所を壊します。

このラボとソースについて: 毎日使う Linux コマンドのラボ:エンジニアが暗記している30のコマンド

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。