「Pythonの学習をしているけれどもクラスっていまいち理解できないな」
「クラスってどういった場面で使うものなの?」
今回はこういった悩みをもつ初学者の方向けに「クラスの考え方」や「基本的なコードの書き方」をご紹介します。
この記事を読めばクラスについての基礎的な理解を深めることができますので、是非ご一読ください。
プログラムの考え方
クラスを学ぶ上で、まずはプログラムの考え方についての知識を深めておきましょう。
プログラムの見方・考え方の枠組みのことを「プログラミングパラダイム」と言いますが、Pythonには「手続き型プログラミング」と「オブジェクト指向プログラミング」といった考え方があります。
考え方 | 特徴 | メリット | デメリット |
手続き型プログラミング | コンピューターが実行するプログラムの内容を順番に記述する方法 | コードの記述が容易 | コードの再利用やメンテナンスが困難 |
オブジェクト指向プログラミング | プログラムを処理対象(オブジェクト)ごとに構成して記述する方法 | コードの再利用やメンテナンスが容易 | コードの構成が複雑 |
上の表のようにそれぞれの考え方には長短所がありますが、Pythonでは状況に応じてプログラムを組み立てることができます。
「手続き型プログラミング」は処理順にコードを記述するため、他の考え方と比較すると「可読性が高く学習コストが低い」とされています。ただしその一方で、コードの再利用が難しく、処理の都度コードを記述する必要がある点もあげられます。
そういった点を補完するための考え方が「オブジェクト指向プログラミング」です。
「オブジェクト指向プログラミング」では、プログラムを「オブジェクト」単位で記述して、それを組み合わせるかたちでプログラムを構成します。
なお、ここでの「オブジェクト」とは、単に「モノ」といった意味合いではなく、「コンピューター上での処理対処となるモノ」を指します。
クラスとは
上述のとおり「オブジェクト指向プログラミング」では、プログラム上で扱う対象を「オブジェクト」に見立ててコードを記述しますが、その中で「設計図」のような役割を担うものが「クラス」です。
「オブジェクト指向プログラミング」では、「クラス」をつかって作成した「設計図」をもとに「オブジェクト」を生成したうえで、それらを組み合わせることによってプログラムを構成します。
そのため、「オブジェクト指向プログラミング」では「クラス」が中心的な役割を担います。
「手続き型プログラミング」と比べて、「クラス」をもちいた「オブジェクト指向プログラミング」はコードの構成が複雑になる傾向がありますが、コードの再利用やメンテナンスには適した記述方法であると言えます。
そのため、「オブジェクト指向プログラミング」は大規模なコードを作成するときにメリットを享受することができます。
では、「クラス」はどのように構成されているのでしょうか?
概念的な説明だけではイメージが難しいかと思いますので、具体的なコードを使って確認をしましょう。
クラスを使ったコード作成例
こちらでは具体的なクラスの記述方法をお伝えします。
クラスの構文
クラスの構成は以下のとおりです。
class クラス名:
クラスの定義の記述
クラスの定義
まずはこちらの例をつかって基本的なクラスの定義方法を確認しましょう。
class EnemyStatus: def __init__(self, hit_point, magic_point): self.hit_point = hit_point self.magic_point = magic_point
クラス名のつけ方
「命名規則」のルールによれば、クラス名は「頭文字は大文字」で「大文字での文字区切り」とされています。具体的には「MyClass」のような形でクラス名を定義することが求められています。
「def」
「def」はクラスで「関数」を定義をする際に使用します。
クラス内で宣言される「関数」は、正確には「メソッド」と呼ばれています。
ちなみに「関数」とは、ざっくり言えば「与えられたデータに対して決められた処理を行うための機能」のことです。
「__init__」
「__init__」は、コンストラクタと呼ばれているもので、「クラス」から「オブジェクト」を生成した際に実行される関数のことです。
コンストラクタは、クラスの「設計図」から「オブジェクト」を生成する際に「初期状態」を設定する目的で使用されます。「初期状態」を明確に設定することによって、例えばコードの再利用をするタイミングでの設定ミスを予防することができます。
「self」
第一引数に設定されている「self」は、「オブジェクト自身」を指します。
クラス内で宣言される「関数」は「メソッド」とお伝えしましたが、Pythonではこの「メソッド」の呼び出しは「オブジェクト自身」を引数として渡さなければならない設定がされているため、「self」を明示的に記述する必要があります。
なお、引数名は必ずしも「self」である必要はありませんが、可読性を高めるためにもPythonで慣例的に使用されている「self」を使用しましょう。
スポンサーリンク
オブジェクトの生成
クラスで定義した「設計図」に基づいて「オブジェクト」を生成します。
なお、クラスで生成された「オブジェクト」のことをより具体的に表現する目的で「インスタンス」と呼ぶ場合もあります。
このような形で変数に代入することによって「インスタンス」を生成します。
enemy1 = EnemyStatus(100, 10)
このように記述することによって、生成した「インスタンス」から値を取得することができます。
print(enemy1.hit_point) print(enemy1.magic_point)
こちらが出力結果です。
「インスタンス」生成のさいに設定した値を取得していることが確認できます。
100
10
インスタンスメソッドの定義
クラスのなかに作られた「関数」のことを「メソッド」と呼ぶとお伝えしましたが、正確には「インスタンスメソッド」という名称が与えられています。
クラス「EnemyStatus」のなかにインスタンスメソッド「show」を定義します。
6行目にて、さきほどの「__init__」と同じように、第一引数には「self」を記入します。また、print関数のなかの値も「self.hit_point」のように明示的に「オブジェクト(インスタンス)」を指定しています。
class EnemyStatus: def __init__(self, hit_point, magic_point): self.hit_point = hit_point self.magic_point = magic_point def show(self): print("HP:", self.hit_point, "MP:", self.magic_point)
クラスの定義が完了したら、「オブジェクト(インスタンス)」を生成します。
enemy2 = EnemyStatus(200, 5)
生成された「オブジェクト(インスタンス)」に対して、定義したインスタンスメソッド「show」を呼び出します。
enemy2.show()
こちらが出力結果です。
HP: 200 MP: 5
クラスメソッドの定義
クラスにはもうひとつ「クラスメソッド」というメソッドがあります。
インスタンスに紐ついているメソッドのことが「インスタンスメソッド」と呼ばれているのに対して、クラスに紐ついているメソッドのことは「クラスメソッド」と呼ばれています。
「クラスメソッド」の定義のポイントは以下のとおりです。
- デコレータ「@classmethod」を記入する
- 慣例的に第一引数を、「self」ではなく、「cls」とする
※詳細は割愛しますが、「デコレータ」とは関数を修飾するための機能のことです。
「インスタンスメソッド」と「クラスメソッド」との大きな違いは、クラスから直接メソッドを呼び出せるかどうかにあります。「インスタンスメソッド」は直接メソッドを呼び出せませんが、「クラスメソッド」では可能です。
具体的なコードで「クラスメソッド」の確認をしましょう。
class EnemyStatus: def __init__(self, hit_point, magic_point): self.hit_point = hit_point self.magic_point = magic_point @classmethod def check(cls): print("こちらはクラスメソッドです")
以下のコードを実行してみましょう。
EnemyStatus.check()
出力結果はこちらです。
こちらはクラスメソッドです
では、「インスタンスメソッド」との動作比較をしてみましょう。
デコレータ「@classmethod」の記述がなく「第一引数」が「self」である、といった違いがあります。
class EnemyStatus: def __init__(self, hit_point, magic_point): self.hit_point = hit_point self.magic_point = magic_point def check(self): print("こちらはインスタンスメソッドです")
以下のコードを実行してみましょう。
EnemyStatus.check()
こちらが実行結果です。
クラスから直接メソッドを呼び出すことができませんので、エラーが発生しました。
TypeError: check() missing 1 required positional argument: 'self'
まとめ
「オブジェクト指向プログラミング」といったプログラムの考え方と、具体的なクラスを使ったコードの記述方法をご紹介しました。
「手続き型プログラミング」とくらべて「オブジェクト指向プログラミング」はイメージが難しいため、学習を進める上ではつまずきやすいポイントではあるかと思います。
Pythonでは、いずれの考え方でもコードを記述することができますので、無理に使う必要はありません。
そのため、学習を始めたばかりの場合は基本的な考え方だけおさえておけば問題ないかと思います。