産婦人科についての内容は「note」で随時公開しています。こちらをご参照ください。

【python】オブジェクト指向型プログラミングの3原則【継承・多様性・カプセル化】

python オブジェクト指向プログラミング

こんにちわ。

今回は前回の「オブジェクト指向型プログラミング」に引き続き2回目になります。python オブジェクト指向プログラミング【python】オブジェクト指向プログラミングの基本【分かりやすく解説】

前回のテーマ
  • オブジェクト指向型プログラミングの特徴を理解する
  • クラス型とデータ型について理解する
  • クラス定義について理解する

今回のテーマは、オブジェクト指向型プログラミングを仕様する際のキモとなる、3原則(継承, 多様性, カプセル化) についてです。

では早速みていきましょう。

オブジェクト指向プログラミング:継承

python オブジェクト指向プログラミング 継承

オブジェクト指向型プログラミングには、下記の3つの特徴があります。

  • 継承
  • 多態性
  • カプセル化

各々について、まずは継承からみていきましょう。

継承とは、あるクラスの特徴を他のクラスが受け継いだ上で、さらに他の特徴も加わることを言います。

A というクラスがあり、B というクラスが A を継承する場合、A を親クラス(スーパークラス)、B を子クラス(サブクラス) と呼んでいます。

継承を利用して、定義がほぼ同じのクラスは、その定義を親クラスに集約させ、子クラスで継承するという形でコードを記述すれば、同じようなことを何度も書く面倒さが無くなります。

以下の記事で使用したファイルを使用して具体的に解説していきます。python オブジェクト指向プログラミング【python】オブジェクト指向プログラミングの基本【分かりやすく解説】

この記事で記載しているCat と Japanese_Cat の関係で継承を利用してみましょう。

この CatJapanese_Cat の2つのクラスの性質を新しく設定したNew_Cat というクラスに集約します。

その子クラスに English_Cat (前回の記事で Cat としていたクラス)とJapanese_Cat に用意して、ファイル cats.py を変更してみましょう。


親クラスとする Cat にインスタンスメンバ変数 name とコンストラクタを定義します。


Japanese_Cat のコンストラクタ

親クラスの Cat のメソッドはsuper().メソッド() と書くことで定義できます。

ここで super().__init__()と記述し、親クラスの Cat のコンストラクタを name の値だけ渡して実行しました。(コンストラクタは __init__ で定義されます。)

コンストラクタでの処理が同じような内容になるのであれば、このように記述することで、重複した処理の記述を防げます。

元々の Cat クラスは English_Cat クラスに変えたので、use_cats.py も変更しておきます。

use_cats.py


実行すると以下の様になります。
変更前とほとんど変わらないのが分かります。

オブジェクト指向プログラミング:多態性

python オブジェクト指向プログラミング 多様性

オブジェクト指向プログラミングには多様性という性質があります。


多様性はポリモーフィズムということもあります。


多態性(ポリモーフィズム)
は、すなわち、同じ名前(メソッドなど)で多くの処理を実行できる仕組みのことを言います。


多態性の仕組みは2種類あります。


ひとつは、オーバーライドです。これは親クラスのメソッドを子クラスで上書きして別のものにするという特徴があります。


もうひとつは、オーバーロード です。これは引数の数の違いで分ける事が出来ます。

オーバーロードは引数が違う形で、同じ名前のメソッドを多数定義できる仕組みです。

しかしPythonにはオーバーロードは実装されておらず、オーバーロードぽいこともできるのですが、今回は省略とさせていただきます。

オーバーライド

先ほどの cats.py を、オーバーライドを利用してみましょう。

cats.py

voice というクラスメンバ変数を追加しました。

scream() メソッドで利用しています。

先ほどの Cat ではコンストラクタのみ定義していましたが、scream() も description() も親クラスの Cat で定義しました。

このようにすれば、継承の性質により、子クラスの English_Cat と Japanese_Cat で、親クラスでの定義内容そのままで実行できます。

そのため、子クラスでは scream() の定義を記述していません。

しかし、description() については定義を上書きしなければ「世界のネコの鳴き声は」と表示されてしまいます。

そこで、それぞれの子クラスで description() を定義して、親クラスで実行される内容を上書きしています。

その結果、「米国のネコ」「日本のネコ」と表示されます。

以下のように use_cats.py を変更の上、実行確認してみてください。

use_cats.py

実行結果は以下の様になります。


今回はクラスメソッドをオーバーライドしました。

同様に、インスタンスメソッドもオーバーライドをする事ができます。

また、下に記載しているコードのようにメンバ変数を追加することで、オーバーライドをしなくても済んで、さらにコードの記述量を減らす事ができます。

cats.py

オブジェクト指向プログラミング:カプセル化

python オブジェクト指向プログラミング カプセル化

オブジェクト指向プログラミングにはカプセル化という性質があります。

カプセル化
は、変数をオブジェクトの内部に隠すことを言います。

そうすることで、カプセル化された自分以外のオブジェクトがメンバ変数=プロパティを参照できない様にできます。

ここで新しくは human2.py と use_human2.py を作り、まずは以下のようにコードを書いてください。

human2.py

use_human2.py

通常は、上記のように Human クラスのメンバ変数 name には use_human2.py から参照できます。

しかし、2つのファイルを以下のように書き換えてください。

human2.py

use_human2.py

メンバ変数 name の名前を __name に変更しました。

頭にアンダーバーを2個つけただけです。しかし、実行すると 'Human' object has no attribute '__name' と出てエラーになります。

エラー内容に書かれているとおり 「__name が見つからない」という旨のエラーです。

つまり、メンバ変数 __name はカプセル化された状態で、Humanクラスの中でしか __name に直接アクセスすることができません。

これがカプセル化です。

ただしPythonのカプセル化は完全なカプセル化ではありません。

use_human2.py を以下のように書き換えると、Cloud9のエディタでは赤いバツ印が表示されますが、python use_human2.py は実行でき、「田中」「青木」が表示されてしまいます。

use_human2.py

記述方法は インスタンス変数名._クラス名__メンバ変数名 です。

クラス名の前はアンダーバー1つ、メンバ変数名の前はアンダーバー2つです。

ただし、この方法は、オフィシャルで仕様として実装されている機能であるとはいえ、多用するのは「お作法」として良くありません。

より良い「お作法」は、ゲッター と セッター と呼ばれるメソッド経由でカプセル化した変数の中身を参照(上書き)する方法です。

メソッド経由で情報を参照(上書き)することで「誰が、どのタイミングでアクセスしたか」の証跡を残すなどの対応ができるので「誰かわからない人に突然情報を見られた(書き換えられた)」ということがなくなり、安心です。

先ほどの2つのファイルを以下のように変更し、use_human2.py を実行して、正しく「田中」「青木」と表示されることを実行確認してください。

human2.py

use_human2.py

まとめ:継承・多様性・カプセル化

python オブジェクト指向プログラミング

この記事ではオブジェクト指向プログラミングについて学びました。


Python上ではデータがオブジェクトの形をしているので、オブジェクト指向のプログラミングの知識はPythonだけではなく多くのプログラミングを扱う際に役立ちます。


さらに、これからの記事で「パッケージライブラリ」について学びますが、自分でライブラリを作る際にもオブジェクト指向プログラミングの性質を扱う様になります。


はじめてオブジェクト指向プログラミングに触れた方は、よく復習しましょう

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください