婦人科疾患に関する内容はこちらをご覧ください。

【python】オブジェクト指向プログラミングの基本【分かりやすく解説】

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

こんにちわ。


今回は以下の様な疑問を持っている方に対しての記事になります。

「オブジェクト指向プログラミング」とは何なのか、具体的なイメージがつかめません。

「オブジェクト指向プログラミング」について具体的なイメージから使い方まで知りたいです。
まず、プログラミングにはいくつか種類があることを押さえておきましょう。
プログラミングの種類
  • オブジェクト指向プログラミング:オブジェクト=モノを組み立てて作り上げていくプログラミング
  • 手続き型プログラミング:単調なルールにのっとったコードで動くプログラミング
  • 関数型プログラミング:関数を使って動くプログラミング

オブジェクト指向型プログラミングにはpython以外の他の言語では、RubyやPHP, Java, Java Script があります。


では、オブジェクト指向型プログラミングとはどの様なものか、具体的に見ていきましょう。

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

早速見ていきましょう。

オブジェクト指向型プログラミングについて

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

オブジェクトとは、家具や机、ペットの犬、猫、学校の同級生やあなた自身など、その辺にある全てのモノのことを言います。


要するに、オブジェクトとはモノのことであり、pythonのプログラミングで扱われる対象全てのことを意味します。


ここで、オブジェクトがネコであった場合を仮定します。

オブジェクト指向型プログラミング 猫
ネコであれば、「名前」「血統書」「年齢」「性別」「体重」などの情報があります。


これらネコの属性のことをプロパティと言います。


さらにプロパティのことをオブジェクト=ネコのメンバ変数と言います。


そのほかにネコは「じゃれる」「食べる」「逃げる」「飛ぶ」などの行動をします。


このオブジェクト=ネコの行動(=振る舞い)のことをオブジェクトのメソッドと言います。

オブジェクトの認識番号とは

オブジェクトのIDの確認方法

世界であるヒトがたった一人しかいない様に、pythonにおいてもオブジェクトはたった一つしかありません。


たった一つであることを確認するためには、オブジェクトのID(認識番号)を調べれば分かります。


オブジェクトのIDの値を知るためには、id() を使用します。引数の () には、オブジェクトを代入します。


実際にIDを知るためのコードを書いてみましょう。


Pythonでは、数字であれ文字であれ、同値のデータであればIDが同じになります。

この様に sanfusanfu2 では記載の仕方が異なりますが、データは”sanfujinkainotechou” であるためにidが同じになります。


しかし、シーケンスのタプルの場合にはオブジェクトが同じ内容であったとしても、Idが異なることに注意してください。


※ タプルについては以下の記事を参照ください。
python タプル【python】タプルの使い方【基本から応用まで】

この様に、タプルであればidが異なっているのが分かります。


ここで、sanfu1sanfu2をセットに入れてみます。

すると、sanfu1sanfu2は重複データとして判断されてしまい、sanfu1sanfu2 をセットにしても1つのデータしか入っていない事が分かります。


これは sanfu1sanfu2 のデータが重複しているためです。


すなわち、データの内容とidはそれぞれ異なる概念であることを理解しましょう。


異なるIDのオブジェクトをセットに代入しても重複されません。
セットはIDで重複と判断しないのが非常に重要です。

オブジェクトのハッシュ値の確認方法

sanfu1sanfu2 は異なるidを持ちますが、セットにすると重複データとして判断されてしまいました。


このようにセットはIDでオブジェクトの内容を判断していませんでした。セットはIDとは “異なる方法” でオブジェクトを判断しているのです。


それではどの様にして、セットは重複を判断するのでしょうか。


セットがオブジェクトの値が重複しているかどうかは、 ハッシュ値 で判断します。


セットでsanfu1sanfu2 が重複データと判断された事とは逆の現象が、ハッシュ値によって起こり得ます。


オブジェクトが違っていても、オブジェクトの中身のデータが同じものであればハッシュ値は同値になる事があります 。


ここで、先程の sanfu1, sanfu2 についてハッシュ値を調べてみましょう。


ハッシュ値を調べるためには hash() で可能です。

この様に sanfu1sanfu2 ではIDが異なっていても、ハッシュ値が同じであることが分かりました。


すなわち、セットで sanfu1, sanfu2 が重複していたのは、sanfu1sanfu2 のハッシュ値が同じであったからなのです。

== はデータが同じ」、「is はハッシュ値が同じ」

==is の違いについてまとめておきます。


== はハッシュ値が同じかどうか!= はハッシュ値が異なるかどうかを調べる演算子です。


一方でis はIDが同じかどうかis not はIDが同値ではないかを調べる演算子です。


この2点の違いに注意してまとめておきましょう。

 同値同値ではない
ハッシュ値==!=
IDisis not


先程のsanfu1, sanfu2についてみてみましょう。

オブジェクト指向プログラミングの特徴

オブジェクトの判別の仕方がわかったところで、本題の「オブジェクト指向プログラミングの特徴」について見ていきましょう。

オブジェクト指向プログラミングの特徴としては以下の様にまとめることができます。

  • プロパティを持つ (シャム猫、エルルちゃん、etc)
  • メソッド を持つ(じゃれる、寝る、etc)
  • 各オブジェクトは独自の識別番号IDを持つ
  • オブジェクトオブジェクトの間に関係性を持たせる

pythonでプログラムを作成するときにはこれらの特徴を利用します。

クラスとデータ型

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

データ型には123 などの数値型、"abc" なども文字列型があります。


これらのデータ型は クラス として定義されています。


というのも、組み込み関数の一部(int etc…)はクラスとして定義(実装)されています。(int は関数ではありません。int はクラスオブジェクトです。)


クラスとは要するにデータが属するグループのことです


ネコ科の、とあるシャム猫がオブジェクトとします。


このシャム猫のオブジェクトを設定するにはネコ科というクラスを定義する必要があります


オブジェクトのプロパティ、メソッドの関係性はクラスの中で定義されます。


ネコ科
というクラスのなかでオブジェクト(=とあるシャム猫)を定義します。
ネコ科というクラスから作られたとあるシャム猫 = オブジェクトのことを インスタンス と呼びます。


ここで、まとめです。

クラス・オブジェクト・インスタンス
  • オブジェクト(対象)はクラスにそって生成される。
  • 同じクラスから別々の個性を持ったオブジェクトを生成する事ができる。
  • 「ネコ」のクラスの「エルルちゃん」であった場合↓
  • 「エルルちゃん」は「ネコ」のクラスの「インスタンス」
  • 「クラス」は分類枠であり、「インスタンス」は個体
ここで更に、クラスとインスタンスの関係について深掘りしていきましょう。

クラスとインスタンスの関係

クラスとインスタンスの関係で重要な項目は以下の3点です。

以下のサイトから引用します。

  • クラスは雛形で設計図のようなもの
  • インスタンスはクラスから作られる実体
  • インスタンスにどのようなデータを持たせるかはクラスで定義する

両者はちょうど、「たい焼きの型枠」と「たい焼き」のような関係かもしれません。

「たい焼き」はその枠型という設計図に従って量産されますよね。

どういうたい焼きを焼きたいかによって、そのもとになる「たい焼きの型枠」が変わってきます。

いったん型枠さえ作ってしまえば、何個でも実体としてのたい焼きが作れます。

クラスもこれと同じで、どういうようなデータや処理を持ちたいかによって、どういうクラスを作るかが変わってきます。

そしていったんクラスを作ってしまえば、インスタンスは好きなタイミングで好きな数だけ作ることが可能です。

>> Pythonで学ぶ基礎空のプログラミング入門 (オブジェクト指向について学ぼう)


この様にクラスとインスタンスの関係は “たい焼き” で理解すると分かりやすいです。

クラスの定義

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

クラスを作ってみる

クラスはintなどだけではなく、自分で定義することも出来ます。


実際にクラスを作ってみましょう。


ここではネコと言うクラスを作ってみます。

オブジェクト指向型プログラミング クラス 猫

ネコにしても、ヒトにしても、カピバラにしても、あるクラスを定義するには class を使って定義します。


whileiffor, でもあったようにインデントを入れて改行している部分がクラスにかかっている(共有範囲)となります。

早速クラスを定義してみましょう。


以下の内容を記載して cats.py というpython のファイルを作成してみてください。

まずこの Cat クラスで、nyan というプロパティと、scream というメソッドを定義しました。

プロパティ(メンバ変数)

cats.py の中でメンバ変数の定義部分は、こちらです。(メンバ変数とはプロパティのことです)


voice = "nyan!"


今までの変数の定義と同じです。クラスの中で、このように記述すると、メンバ変数を1つ用意したことになります。


ここでは voice というメンバ変数を定義しました。つまり、ネコの「鳴き声」です。


ネコちゃんですから "nyan! という鳴き声で定義しました。


このように定義した”nyan!” というメンバ変数を クラスメンバ変数 と言います。

メソッド

まずは、メソッドに対する概念の復習です。


メソッドの使い方は「オブジェクトに「 .」 をつけて、メソッドを実行」します。たったそれだけです。


例えば、 Tommy.職業 であれば 産婦人科医 と出力される様なものです。


そのほかの例をあげていきます。

ここで実習として「ネコ」を実装するファイルを実装してみましょう。


cats.py のファイルを作成しましょう。


cats.py の中でメソッドの定義部分は、こちらです。(一部抜粋しています)

メソッドの定義も、関数の定義と同じです。 def を使うだけでokです。


output での画面表示は self.voice にしています。


これは、self の属性としての voice を意味しています。


ネコが鳴き声を表示する処理なので、メソッド名を scream() (ニャン❤️)としています。


ここで重要なポイントを押さえておきましょう。

ポイント
  • 1番最初のメソッド名(引数)の引数には self を入れてください。
  • 今回のcats.py であれば scream(self) の様に記載します。
  • self自分自身のオブジェクトを指すキーワードです。
  • self.変数名 や self.メソッド名() といった書き方をすることで、自身が持つオブジェクトを持つプロパティを参照したり、メソッドの実行が可能です。
  • self.変数名 や self.メソッド名()はプロパティやメソッドの実行を行うために必要なキーワードです。
    以上を押さえておきましょう
大事な点なので繰り返しになりますが、
  • self がつくとメンバ変数(プロパティ)
  • self がついていなければ、外部から代入された変数
とおさえましょう。

プロパティやメソッド、オブジェクトの用語が不安な方は以下の記事を参照にしてください。すぐに把握できます。python コード サンプルpythonコードのサンプル【初心者向け】オブジェクトとメソッドメソッドを記載する時には、self.メソッド名(引数) という形で記述してください。

self.メソッド名(引数) の様な書き方のこのタイプのメソッドは インスタンスメソッド といいます。

クラスのインスタンスについて

では、この Cat クラスのインスタンスメソッドを作ってみましょう。


cats.py のファイルはそのまま保存し、新しくuse_cats.py というファイルを作成しましょう。


作成したら以下の記述を行なってください。実行すると下の「nyan!」が表示されます。

最初にまず Cat のクラスのインスタンスメソッドをインポートしましょう。
(※ インスタンスメソッドとは、self.メソッド名(引数) の様な書き方のこのタイプのメソッドです。)


そのために、最初に from ファイル名 import クラス名 と記述してください。


今回であれば、from cats import Cat としましょう。


この様に記載することで、cats.py に定義されたクラスであるクラスの Cat をimportする事が出来ます。


次に、インスタンスを作成してみましょう。

self.メソッド名(引数) このタイプのメソッドは インスタンスメソッド といいました。

インスタンス = クラス名() と記述します。


この様に記載する事で、初期の何も情報のない真っさらなクラスCat()をインスタンスである変数 kitty に収納する事ができます。
(ここで、初期である理由は Cat()() に何も入れていないからです。)


これだけでは何も起こらないため、scream() メソッドを実行しましょう。


オブジェクトの変数名.メソッド名(引数) すなわち、
kitty.scream() と記述します。

コンストラクタ

クラスCat のメンバ変数である voice (鳴き声)は、すべてのCatに属しているネコで nyan! と出力されます。(※ メンバ変数とはプロパティの事です。)


ところでですが、クラスCatには多くのネコがいるはずです。


そこでCatに所属する1匹1匹のネコちゃんに、異なる「プロパティ(メンバ変数)」 = 「name(名前)」を持たせてみましょう。


実際に行う方法としては、インスタンスごとに異なる値にしたいプロパティ(メンバ変数)を コンストラクタ という方法で作成します。


コンストラクタ は、 __init__ で定義されます。


init の前後には __ が2つくっついてきますので覚えてください。


Cat クラスの場合で考えてみましょう。


cats.py のファイルに上書きしていきましょう。

コンストラクタ __init__ の中で変数 nekochan を定義しました。


この nekochan は外部より入ってきた変数です。


引数にある nekochan = "Kitty" が、その定義部分です。


(def__init__ の後に続く self は引数で、nekochan は第二引数と言います)


nekochan に指定がなければ自動的にデフォルトで "Kitty" という名前になるように設定しています。また、__init__ の処理の中に

このように書きました。


これで、名前の指定があった場合に、指定された名前(例えばnekochan = "Eruru" など)をメンバ変数 name へ代入するように、インスタンス作成時の初期処理として定義しています。


左辺の self.nameCat クラスのインスタンスメンバ変数 name、右辺の nekochan はコンストラクタの引数に指定された変数 nekochan です。


ここで定義したメンバ変数nameインスタンスメンバ変数 と言います。


この新しい Cat クラスを使用して、use_cats.py を書き換えてみましょう。

kitty の他に Eruru という Cat クラスのインスタンスを作成しました。


それぞれ、名前は KittyEruru です。


インスタンス変数名.name で名前を参照し、インスタンス変数名.scream() で scream() メソッドを実行しています。

クラスを人間で作ってみる

ここで、ネコだけでは実感がつかないかもしれませんので、人間でもクラスを作成してみましょう。


まずは情報の何も入っていないまっさらなファイル keio_human.py を作成します。


そして以下の記載をしてください。

次に出力用のファイルを作成します。 human.py とでもしておいてください。

ここで、実際に出力したファイルが以下の様になっています。

実際に色々試してみましょう。

クラスメソッド

ここで「インスタンスメンバ変数」「クラスメンバ変数」「インスタンスメソッド」という言葉が出て他ので、それぞれについて解説していきます。

インスタンスメソッド

インスタンスメソッドとは、クラスの中に記述したメソッドのことです。


各インスタンスが動く様なイメージです。


【例】Cat クラスの scream() メソッド

クラスメンバ変数

そのクラス、および、クラスに属するインスタンス全てに共通するデータが定義された変数。


要は定数みたいなもんです。


【例】Cat クラスのメンバ変数 voice

インスタンスメンバ変数

インスタンスごとに収納されている変数です。


【例】Cat クラスのメンバ変数は name です。

「インスタンス」→ インスタンスメンバ変数インスタンスメソッド に関係

「クラス」→ クラスメンバ変数

「クラスに紐づくメソッド」→ クラスメソッド です。

クラスメソッドは クラス名.クラスメソッド() と記載してもokです。


ここでCat クラスに「ネコは “nyan!” と鳴く」ことを意味づける description() でクラスメソッドを定義してみましょう。


cats.py を変更します。

続けて、実行する use_cats.py も変更します。

実際に、実行してみましょう。

ここで、クラスメソッドを使用する場合には、

この1行を def メソッド名(引数): の行の上に付け加えます。


これをつけたメソッドがクラスメソッドとして扱われます。


Cat クラスのクラスメソッド description() を使用する場合には、Cat.description() と記載することで使用する事が出来ます。

ほかのクラスを作ってみる

ほかの「日本のネコ(Japanese_Cat)」というクラスを作ってみましょう。

ここで出力用のファイル use_cats.py の最初の一行目を

この様に変更します。


そうすることによって、Japanese_cat クラスもインポート出来る様になります。


そうしたら、既存の Cat クラスの記述はそのままにして、ファイルの末尾に以下の内容を追記し、最終的にuse_cats.py は以下の様に書き換えます。

出力した結果は以下の様になります。

このように、1つのファイルの中に2つ以上のクラス定義を記述できます。


しかし、Cat とほぼ同じようなことを書かなければならなかったため、面倒だったかと思います。

まとめ|オブジェクト指向プログラミング

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

如何でしたでしょうか。


今回はオブジェクト指向について基本的なことから解説していきました。


新しい名称がたくさん出てきますので少しややこしいですが、一つ一つ覚えていけば必ず身につきます。


「self の箇所でつまづいてしまった」というコメントが多かったですので、ここで重要なポイントをまとめておきます。

今回のまとめ①
  • 「クラス」とは、オブジェクトを作成するためのテンプレート。
  • 「クラス」には実態はなく、「クラス」はデータ構造を設計する分類枠。
  • 「クラス」に沿った形で「インスタンス」は生成される。そこで生成された「インスタンス」は固体となる。
  • 重要なことは、「インスタンス」が最初に生成された際には初期化を行う。
  • 「インスタンス」とは「クラス」の定義に従って属を持つオブジェクトである。
  • 「プロパティ」には属性を与える。「 .  」を付ける。
  • クラス内に「メソッド」を定義した際には、仮引数に必ず「self」を付ける。

self.変数名 や self.メソッド名()など。。。

  • self がつくとメンバ変数(プロパティ)となる。
  • self がついていなければ、外部から代入された変数となる。
この違いを押さえておきましょう。

今回のまとめ②
メソッドの書式はある程度決まっていますので、以下の書式と流れをおさえておきましょう。

  • __init__” は「コンストラクタ」の定義の方法である。
  • オブジェクト生成時は必ず __init__ に self を加えることで初期設定を行う。
  • クラスに沿ったオブジェクトを生成する。(同じクラスから別々のオブジェクトを生成する事が可能)

    例として以下のものをあげておきます。

まずはこの書式に慣れてください。

今回のテーマはpython学習の中でも一つのヤマですので、頑張って乗り切りましょう。

コメントを残す

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

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