Python3超入門講座【第12回】「クラスとオブジェクト」


さて、Python3習得の最難関。つまづきの石。クラスとオブジェクトにやってまいりました。存分に「うんうん」・「はぁはぁ」悩んでしまう難所です!

このオブジェクトというのはなかなか厄介な概念ですぐには理解できないのが普通です。

「クラスってなんなんじゃーーーーー」著書も、生まれてはじめてJava言語を勉強したときに、かなり混乱しました。

「解説を読んでも読んでもわからねーーーーー!」と悩んだものです。

オブジェクト指向はこのように苦しんで覚えるものです。しかし、本稿では、そんな馴染みにくいクラスの概念を、明快にわかりやすく解説しております!!!

クラスとは何か

クラスというのは簡単に言えば「たい焼きの鋳型」です。別の例えをすれば、設計図とも言えるでしょう。

なので、クラスそのものは役に立ちません。たい焼きの鋳型だって、パソコンの設計図だって、それ自体では役立たないのと同じことです。

パソコンの設計図やたい焼きの鋳型から、実際に使えるパソコンを製造したり、実際に食べられるたい焼きをつくらなければ意味がありませんね。

クラスを元に実際的に意味のある実体を作り上げることをインスタンス化と呼びます。

これは例えばたい焼きの鋳型に材料を流し込んで、実際に食べられるたい焼きをつくるようなものです。

ここでいう、たい焼きの鋳型がクラス、実際に食べられるたい焼きがインスタンスです。

クラスを書いてみよう

それでは実際にクラスを書いてみましょう。最初は単純なクラスのサンプルコードからはじめ徐々に複雑なクラスを書いていきます。

最も単純なクラスのサンプルコード

クラスを作成するには以下の書式を用います。

class クラス名(クラス名は大文字で始める):
        クラスを定義するコード

今回のPersonクラスは、とっても単純なクラスなので、クラスを定義するコードの部分は、age = 22だけです。

尚、このようにクラス内で用いられる変数をプロパティと呼びます。

従って、上記サンプルコードのPersonクラスは、ageプロパティ1個だけを持ったクラスってことになりますね。

尚、慣例上、クラス名は大文字で始める点にも注意して下さい。

別にクラス名を小文字でpersonとしても、文法エラーにはなりませんが、「クラス名は大文字ではじめる」という礼儀作法のようなものがあるのです。

次にクラスをインスタンス化(実体化)します。クラスという設計図を元に、実体を生成するわけです。

インスタンス化の書式は以下の通りです。

変数 = クラス名()

こうすることで、変数はクラスのインスタンス(実体)を参照するようになります。尚、このようにクラスのインスタンスを参照する変数のことを特にオブジェクト変数と呼ぶこともあります。クラスのインスタンス(実体)を参照する変数はちょっと普通の変数とは性質が異なるのです。

上記のサンプルコードでインスタンス化している部分は以下です。

psn = Person()

次は、クラスで定義したプロパティ(age=22のこと)へのアクセス方法です。プロパティにアクセスするには以下の書式を用います。

オブジェクト変数.プロパティ名

例:obj.property

ちなみに、プロパティ(property)は、「ある物体の性質を表すもの」を意味します。

Personクラスは「人間」を表すクラスです。そして人間の性質にはいろいろあります。年齢だけではなく、職業や性別、名前や住所などがありますね。その他、挙げればキリがないほど様々な性質があります。

今回は、最も単純なクラスを定義することで、読者様にクラスに慣れて頂くことが目的ですので、age(年齢)しかプロパティを持たせないようにしました。

で、このageプロパティにアクセスするには、psn.ageと書きます。

ageの値は22ですから、psn.ageも22を表します。

従って、print(psn.age)とすると画面に22と出力されます。

次はもう少しだけ複雑なクラスを書いてみましょう。複雑って言っても簡単なので安心して下さい。

ここまでのまとめ

  • クラスはたい焼きの鋳型と同じで、実体ではなく、あくまで設計図的なもの。
  • クラス名は大文字で始める。
  • クラスの中に記述する変数はプロパティである。プロパティとはそのクラスの性質を表すものである。
  • たい焼きの鋳型から、実際に食べられるたい焼きを作るのと同じように、クラスはインスタンス化(実体化)してから使うものである。
  • クラスをインスタンス化するには、「変数 = クラス名()」とする。
  • あるクラスのインスタンスを参照している変数を特にオブジェクト変数と呼ぶ。
  • プロパティにアクセスするには、「オブジェクト変数.プロパティ名」と書く。

もう少しだけ複雑なクラスのサンプルコード

お次はクラス内に関数を含むパターンです。クラスの中に書かれた関数はメソッドと呼ばれます。クラスは、プロパティとメソッドの集まりなのです。

Personクラスにgreet()メソッドを追加しました。よくコードを眺めると、「あれ?」と思われるかもしれません。

クラスを定義している部分をよく見ると、def greet(self):となっています。このselfにはとっても重要な意味があるのですが、それは後述します。今は、クラスの中で関数(正確にはメソッド)を定義するとき、第1引数に必ずselfを指定しなければならない!と覚えておいて下さい。引数が不要なメソッドを書く場合でも、必ず第1引数にselfを指定しなければなりません。そうしないと文法エラーになります。

で、メソッドの呼び出しは以下のような書式で行います。

オブジェクト変数.メソッド名()

なので、psn.greet()とすることで、画面に「こんにちは!」と表示されるというわけです。

で、ここでselfの説明をします。

selfとはクラスのインスタンスを受け取る特別な引数のことです

例えば、psn.greet()というメソッドが実行された際に、psn(=Personクラスのインスタンス)がselfに渡されます。

selfって自分自身っていう意味ですよね?

メソッドはクラスの自分自身のインスタンスを必ず第1引数にとるのです

この処理はPythonが内部的に自動的に行ってくれます。

で、このように解説すると、「それで何が嬉しいの?よくわかんないよ!紛らわしいんじゃ!」と怒り出す方も少なくないでしょう。

そこで、selfへの理解を助けるために、これから間違ったコードを書きます。この間違ったコードを通じてselfへの理解を深めましょう。

selfを理解するための間違ったサンプルコード

このサンプルコードを実行すると以下のエラーメッセージが表示されます。

NameError: name ‘age’ is not defined

日本語に訳すと「ageなんて変数ないんですけど?ない変数を使わないでくれます?」という意味のエラーです。

自己紹介をするメソッドである、self_introduction(self)メソッド内に文法エラーがあります。具体的には、

print(age)

の部分がエラーです。

なぜなら、メソッド内から、メソッドの外側にある変数は参照できないからです。これがエラーになる理由です。

ここで、self_introduction(self)に着目して下さい。このselfって、Personクラスのインスタンスを受け取る引数ですよね?具体的には、psn = Person()のpsnをselfが受け取っております。

で、このPersonクラスのageプロパティにアクセスするには、psn.ageって書けばいいんでしたよね?

で、self=psnなわけですから、print(age)ではなく、print(self.age)って書いてあげれば問題なくageプロパティにアクセスできますよね?

ってなわけで、上記の間違ったプログラムを修正するとこんな感じになります。

13行目が修正した箇所です。このように全てのメソッドの第1引数にselfを設定し、Pythonが内部的に、引数selfに対して、クラスのインスタンスを渡してくれたおかげで、メソッドの外にあるプロパティに容易にアクセスすることができるのです。

図解するとこんな感じです。

Pythonにおけるオブジェクト指向とselfの関係

どうでしょう。selfについての理解が深まってきたでしょうか!?

お次は初期化メソッドについて解説します。

初期化メソッドを含むクラスのサンプルコード1

初期化メソッドというのは、クラスをインスタンス化する際に必ず実行される特別なメソッドのことです。

初期化メソッドはメソッド名を自由に決めることはできません。固定の名前が決められております。

具体的には、def __init__(self):が初期化メソッドです。初期化メソッドもメソッドの一種ですので、忘れずに、第1引数にselfを渡します。

このサンプルコードでは、初期化メソッドの内容は、print(self.os)となっています。osプロパティの値を画面に表示するわけですね。

で、初期化メソッドは、sp = Smart_phone()が実行されたタイミングで自動的に実行されます。

なので、sp = Smart_phone()が実行されたタイミングで、print(self.os)が実行されます。

従ってこのサンプルコードの実行結果は、「Android」と画面に表示される感じです。

お次は初期化メソッドにself以外の引数を渡すパターンを考えてみます。

引数付きの初期化メソッドを含むクラスのサンプルコード

この例では、初期化メソッドにosという引数を渡すようにしています。Javaなどの言語を学んだ方だと、「あれ?プロパティがないじゃないか?」と思うかもしれませんが、サンプルのように書くことでもosというプロパティをSmart_phoneクラスに持たせることができるのです。

sp = Smart_phone(‘iOS’)と書くことで、自動的に__init__(self, os)が実行されます。引数は1個しか指定していませんが、__init__の第2引数(os)に’iOS’がセットされます。

従って、print(sp.os)と書けば、画面に、「iOS」と表示されます。

もう少し実践的なクラスのサンプルコード

実行結果は以下の通りです。

従業員番号:12345氏名:会社花子の情報を管理します。

この社員に関する詳細データを入力する場合は、set_employee_dataを実行して下さい。

set_employee_dataメソッドの詳細は以下の通りです。

age[int], sex[int:1(男性) or 2(女性)], department[st
ring], basic_salary[int], evaluation(int:1~3)

12345
会社花子
29歳
女性
新規事業開発本部/新規事業企画グループ
基本給:250000円
ボーナス額:750000円
評価(1-3):2
社員番号:12345氏名:会社花子の従業員データを保存しました。

サンプルコードの解説。

__init__(self, employee_number=0, employee_name=’会社太郎’)では、引数にデフォルト値を与えつつ、インスタンスを生成するタイミングで、従業員番号(employee_number)と従業員名(employee_name)を指定できるようにしています。

引数にデフォルト値が指定されているので、引数を指定せずに、emp = Employee()と書いてもエラーにはなりません。

set_employee_data(self, age, sex, department, basic_salary, evaluation)は、各プロパティに値を代入するためのメソッドです。

show_employee_data(self)は、従業員のプロパティの一覧を画面に表示するメソッドです。

calc_bonus(self)は、基本給(basic_salary)と従業員の評価(evaluation)を元にボーナスの金額を計算し、その額をself.bonusにセットするメソッドです。

save(self, filename)はテキストファイルに、従業員データ全てを保存するメソッドです。尚、ファイルへの保存方法については、Python3超入門【第13回】で詳細に解説しています。今は細かいコードの内容よりも、クラスを作り、クラスを利用するイメージをなんとなく掴んで頂ければと思います。

以上がサンプルコードの簡単な説明です。

このサンプルコードについてどうしても分からない点があればメールにて質問して頂ければと存じます。

Python3超入門講座トップへ戻る

【関連記事】

あわせて読みたい