第13回 ポリモーフィズム

本題に入る前に必ず連絡の動画を見てください。
Google Colabへのリンク

1. 抽象メソッド

概要

動画の解説を参照

Personクラスを継承して Studentクラスと BusinessPersonクラスを作ってみます。
それぞれには独自の変数として id, salary を持たせます。

Studentクラスと BusinessPersonクラスの両方に、自己紹介を行う introduceメソッドを記述すると、クラス外でインスタンスから呼び出せるようになります。

両方のクラスが introduceメソッドを持つので、例えばこのように StudentとBusinessPerson のインスタンスが混在したリストを作れば、for文でまとめて自己紹介させることもできます。

ただし、これがうまくいくためには、プログラマーが「両方のクラスに完全に同じ名前のメソッド」を実装するために注意しないといけません。
もし片方で微妙に異なる名前になっていたりするとエラーになってしまいます。
(存在しない「introduceメソッド」を呼ぼうとしたときにエラーになります)

このように人間の注意力に依存した実装のしかたは危険なので、それを防ぐ手段があります。
abcモジュールから ABC, abstractmethod を読み込み、基底クラス Personで抽象メソッド として introduceメソッドを実装すると、

BusinessPersonのインスタンスを作ろうとしたタイミングでエラーになります。
どちらも結局エラーになるのでミススペルの問題は解決していないように見えるかもしれませんが、この違いは大事です。
基底クラスに抽象メソッドを実装する前は、(英語的に名前がおかしくても) instroduseメソッドはちゃんと機能するものであり、呼び出すタイミングで「そんなメソッドはない」というエラーでした。
それに対して、基底クラスに抽象メソッドがある場合は、その派生クラスであるStudentクラスとBusinessPersonクラスでは「introduceメソッドを持つ義務」を持つようになります。
つまり、instroduseメソッドがあってもintroduceメソッドがなければ、そのクラスの記述は未完成だということになってしまうわけです。
これによって、誤りに迅速に気づくことができるようになります。
抽象メソッドは継承された先でオーバーライドされることが前提なので、具体的な処理は書きません。
「pass」は何もしないという意味です。
また、抽象メソッドを持ったクラスのインスタンスを作ることはできません。
「基底クラスで抽象メソッドを作り、派生クラスで具体的な処理を書く」というのが基本的な流れです。
同じメソッドに、クラスごとに異なった形を持たせるという意味で、これをポリモーフィズム (多態性 : polymorphism) といいます。

課題1

※ 準備 : 学籍番号を入れて「入力」をクリック (タップ) してください。


このようなクラスに、を追加し、Vectorクラスを継承して空間ベクトルを表す Vector3クラスを作り、追加したメソッドの動作を確認するコードを記述してください。

(例)

2. クラスの判定

動画の解説を参照

前項の解説の3つのクラスがあるとき、isinstanceでインスタンスがどのクラスのものなのかを判定してみるとこのようになります。
つまり、Studentクラス、BusinessPersonクラスのインスタンスは Personクラスのインスタンスでもあるということになります。

これを使った応用を考えてみましょう。
例えば Personとは全く関係ない、ただしintroduceメソッドを持つ Dogクラスを作り、

このようにすれば3つのインスタンスすべてで自己紹介がされますが、

isinstaceで「人」であるかどうかを判定すれば、人に属するインスタンスだけに処理を行わせることができます。

StudentとBusinessPersonは普通に判定できるので、例えば学生と社会人が混在するリストからどちらかに属する人だけに自己紹介させることもできます。

課題2

前項の解説の2番目のコードをベースにして、Studentクラスを継承した ScholarshipStudentクラスを追加し、「奨学生でない学生」「奨学生」「社会人」のインスタンスを少なくとも1人ずつ含むリストを作り、 for文でisinstanceを使ってそれぞれの分類に属する人だけを表示するコードを記述してください。
※ 「奨学生でない学生」「奨学生」のうちどちらかを自分の情報にしてください。
(例)

3. ダックタイピング

動画の解説を参照

長方形と円のクラスを作り、それぞれに面積を返すメソッド get_areaを作るとこのようになります。

どちらも同じメソッドを持っているので、今回の第1項のようにしてFigure(図形)クラスを作って抽象メソッドを継承する形にすることもできますが、面積を得るためだけにわざわざ継承を行うのは大げさです。

そこで、「面積を返せるクラス」という Areableを作ります。RectangleやCircleはこれを継承しません
その代わりに、「面積を返せるクラスのインスタンスを受け取り、その値を取得して表示する」メソッド show_areaをクラスの外に書きます。
これをダックタイピングといいます。
継承よりも緩い方法で、クラス間で同じ名前・意味のメソッドを共有するやり方です。

課題3

「体積を返せるクラス」と「get_volumeをもつクラスのインスタンスを受け取って体積を表示するメソッド」を下図のように書き、get_volumeメソッドを持つを追加し、動作を確認するコードを記述してください。

(実行例)

提出

今回作成したノートブックを「plang2024a@gmail.com」と共有してください。
※ 課題の再提出の際は、ノートブックの再度の共有はせずにチャットで連絡してください。