Pythonのクラスを初心者にも分かりやすく解説します。
クラスの学習を始める前に関数の知識が必須となります。
もし、関数に関して学習が終わっていない方は当サイトの関数に関するページがございますのでそちらを一読ください。
Pythonの関数を初心者でも分かりやすく解説
クラスは何故難しく感じるのか
Pythonのクラスをまずはざっくりと説明します。
Pythonにおけるクラスは簡単に言うとデータ(アトリビュート)と関数(メソッド)を一つにまとめたものを指します。
ざっくりしていて余計分かりにくかったですか?
クラスはよくオブジェクト(インスタンス)を生成する為の設計図とも言われます。
???
もっとわかりにくくなりましたね。
関数の時にも説明しましたが、Pythonは色々な記述が出来る為、クラスを書けなくてもコードを書く事が出来ます。
初学者や初心者がクラスについて躓いてしまったり難しく感じてしまうのは
そもそも初心者の段階ではクラスを使う機会に触れる事が少ない(必要としない)からではないでしょうか。
クラスの書き方を学んでも実際にクラスそのものを単体で使う事はあまりありません。
しかし、クラスを覚える事でオブジェクト指向プログラミングの真価を発揮できるようになります。
何故かというとオブジェクト指向の3大要素にクラスは大きく関わっているからです。
3大要素の一つの継承についてここで軽く触れましょう。
突然ですが、FF5をやプレイしたことはございますでしょうか??
FF5は「すっぴん」という職業から始まります。
「すっぴん」は「たたかう」と「アイテム」の2つのコマンドを行うことが出来ます。
プログラミング風に言うとすっぴんクラス(設計図)を元に主人公バッツを生成(インスタンス化)するわけです。
FF5はジョブシステムがあり「ナイト」等にクラスチェンジする事ができます。
「ナイト」は「すっぴん」が持ってた「たたかう」「アイテム」に加えて「かばう」を行えます。
そして「白魔導士」は「たたかう」「アイテム」に加えて「白魔法」を行えます。
主人公バッツは「ナイト」のジョブに、ヒロインのレナは「白魔導士」のジョブに就いています。
これを継承を使わずに書いてみましょう。「アイテム」は省略しています。
処理は簡単にprint文で行います。
class Suppin:
def __init__(self,name):
self.name = name
def attack(self):
print(f"{self.name}はたたかうを実行しました")
class Knight:
def __init__(self,name):
self.name = name
def attack(self):
print(f"{self.name}はたたかうを実行しました")
def protect(self):
print(f"{self.name}はかばうを実行しました")
class WhiteMage(Suppin):
def __init__(self,name):
self.name = name
def attack(self):
print(f"{self.name}はたたかうを実行しました")
def whitemagic(self):
print(f"{self.name}は白魔法を実行しました")
player1 = Knight("バッツ")
player2 = WhiteMage("レナ")
player1.attack()
player2.whitemagic()
クラスの勉強前ですのでコードはざっくりと読んでもらって大丈夫です。
現段階で意味が分からないのが当たり前です。
これを実行すると
バッツはたたかうを実行しました
レナは白魔法を実行しました
となります。
大事なのは「すっぴん」も「ナイト」も「白魔導士」も「たたかう」が重複している点です。
def attack(self):
print(f"{self.name}はたたかうを実行しました")
「アイテム」は省略していますが、FF5では全22種類のジョブがありますので各クラスに「たたかう」の処理を記述するのは大変です。
しかも、仕様変更などがあった場合これらすべてのコードを書き替える必要があります。
そこで便利なのが継承です。
上のコードを継承を用いて書き直してみます。
class Suppin:
def __init__(self,name):
self.name = name
def attack(self):
print(f"{self.name}はたたかうを実行しました")
class Knight(Suppin):
def protect(self):
print(f"{self.name}はかばうを実行しました")
class WhiteMage(Suppin):
def whitemagic(self):
print(f"{self.name}は白魔法を実行しました")
player1 = Knight("バッツ")
player2 = WhiteMage("レナ")
player1.attack()
player2.whitemagic()
上のコードは「ナイト」と「白魔導士」は「すっぴん」を継承しています。
それにより「ナイト」のジョブに就いているバッツが「すっぴん」クラスの
「たたかう」を実行できています。
継承について本当に軽く説明しましたが(FF5を知らない人は解りにくいかもです・・・)
継承が便利ということは伝わったかと思います。
本記事では継承はこれ以上あつかいませんが、オブジェクト指向プログラミングを使いこなすためにはクラスの知識は必須です。
クラス自体を学んでもいつ使えばいいのか、どこで使えばいいのか分かり難いですが、次のステップへ進むための必須項目と認識して取り組みましょう。
ではここからがクラスの書き方を解説していきます。
クラスの定義
クラスの定義は
class クラス名:
で定義できます。先ほど継承について触れましたが子クラスや派生クラスと呼ばれる継承先のクラスにはクラス名の後に(引数)を指定します。
class Suppin:
これで「すっぴん」クラスを定義できました。
クラス名の先頭は大文字で書きます。これはPythonの公式コーディングルールのPHP8で定められています。キーワードが複数存在する場合大文字で区切ります。
(例:WhiteMage)
メソッド
Pythonを勉強してきてメソッドというキーワードに触れた事はありませんか??
とくに何かしらのライブラリを使う場合に○○メソッドを使用します。
等と記述されていたかと思います。
では、メソッドとは何でしょうか??関数とは違うのでしょうか?
メソッドはクラス内で定義されている関数の事です。
class Suppin:
def attack(self):
print("たたかうを実行しました")
「Suppin」クラスを定義して「attack」メソッドを定義しました。
関数の書き方はdef 関数名(引数):でしたよね。
クラス内で関数(メソッド)を書く場合、必ず第一引数を「self」とする必要があります。
selfは自分自身を表していますが、現段階ではピンと伝わらないかと思います。
今はおまじないのようにメソッドの第一引数は「self」とするとだけ覚えておいてください。
インスタンス化
クラスは設計図のようなものです。とよく説明されています。
これは非常に分かりやすい例えで、クラスは定義しただけでは実行する事はできません。
車の設計図は走らせることが出来ないのと同じです。
クラス内で定義したメソッド等を使用する為にはクラスをインスタンス化する必要があります。
オブジェクト化とも言われます。(厳密には違いがありますが今は区別しなくて大丈夫です。ほぼ同義です。)
では「Suppin」クラスをインスタンス化します。
class Suppin:
def attack(self):
print("たたかうを実行しました")
player1 = Suppin()
これでplayer1というオブジェクトが生成されました。
メソッドの使い方
player1は「attack」メソッドを使用する事ができます。
メソッドを使用する時は
オブジェクト名.メソッド名(引数)とします。
実行してみましょう。
class Suppin:
def attack(self):
print("たたかうを実行しました")
player1 = Suppin()
player1.attack()
これで「たたかうを実行しました」と出力されます。
コンストラクタ
コンストラクタはクラスをインスタンス化する時に実行されるメソッドを指します。
一度コードを書いてみて実行されるタイミングを見てみましょう。
class Suppin:
def __init__(self):
print("コンストラクタが実行されました")
def attack(self):
print("たたかうを実行しました")
print(1)
player1 = Suppin()
print(2)
player1.attack()
print(3)
実行結果は
1
コンストラクタが実行されました
2
たたかうを実行しました
3
となります。
1と2の間で「コンストラクタが実行されました」と出力されているので
インスタンス化された時に実行されている事が分かりますね。
イニシャライズ
__init__は特殊メソッドと言われるものの一つでコンストラクタを作成する為に使用されます。
また厳密に違いはありますが、現段階では深く追求はしないで、コンストラクタ≒イニシャライズ≒イニシャライザという3つのキーワードをほぼ同義でとらえておいてください。
書式やサイトによってコンストラクタ内に○○を記述するやイニシャライズ内に○○を記述するなど、表現方法に違いがありますが、現段階では同義でとらえて差支えはありません。
アトリビュート
クラスはデータ(アトリビュート)と関数(メソッド)をまとめたものと説明しましたが、データと言われてもピンとこないですよね。
コードを書いて解説します。
class Suppin:
def __init__(self,name):
self.name = name
print(f"{self.name}を生成しました")
player1 = Suppin("バッツ")
これを実行すると「バッツを生成しました」と出力されます。
まず、イニシャライザの引数が(self,name)となっています。
クラス内のメソッドの第一引数はselfとなっていますので、nameはこれまで関数で用いられた時の第一引数と実質的に同じ働きをします。
つまりコード最後のplayer1 = Suppin(“バッツ”)の「”バッツ”」はnameに入ります。
続いてself.name = nameでインスタンス変数を定義します。
????
インスタンス変数??急に新しいキーワードが出てきましたね。
インスタンス変数はオブジェクト毎に違う値を持ちます。
今回の場合引数nameをインスタンス変数nameとしています。
インスタンス変数はアトリビュートとも呼ばれます。HTMLを勉強したことがある人は聞きなじみがありますよね!!そうアトリビュートは属性という意味です。
事実インスタンス変数は属性としてのふるまいも行えます。
でわ、player1にバッツ、player2をレナとしてインスタンス化して
それぞれのアトリビュートを見てみましょう。
class Suppin:
def __init__(self,name):
self.name = name
print(f"{self.name}を生成しました")
player1 = Suppin("バッツ")
player2 = Suppin("レナ")
print(player1.name)
print(player2.name)
実行結果
バッツを生成しました
レナを生成しました
バッツ
レナ
アトリビュートは
オブジェクト名.アトリビュートで呼び出せます。
各playerのnameにはそれぞれ”バッツ”、”レナ”が入っています。
クラス変数
インスタンス変数(アトリビュート)は生成されたオブジェクト毎に違う値を持ちます。
しかし、各オブジェクト共通の変数をクラス内に持たせたい場合はどのようにすればいいのでしょうか。
class Suppin:
maker = "スクウェア"
def __init__(self,name):
self.name = name
print(f"{self.name}を生成しました")
Suppinクラスにメーカー名のスクウェアをクラス変数として持たせました。
self.nameはインスタンス変数ですのでオブジェクト毎に違う値が入ります(例:バッツ、レナ)
makerはクラス変数ですので全オブジェクトで共通の値を持ちます。
クラス変数へのアクセス
クラス変数へアクセスするには「クラス.クラス変数」で行えます。
また、インスタンス変数同様「オブジェクト名.クラス変数」でもアクセスできます。
class Suppin:
maker = "スクウェア"
def __init__(self,name):
self.name = name
print(f"{self.name}を生成しました")
print(Suppin.maker)
player1 = Suppin("バッツ")
print(player1.maker)
実行結果
スクウェア
バッツを生成しました
スクウェア
まとめ
この記事ではPythonのクラスを初心者にも分かりやすく解説いたしました。
この記事を読み終えてもいつ使えばいいのか分からない方が大半だと思います。
Pythonを勉強していく過程で初めて関数やクラスに触れるのはTkinter等でのアプリケーション開発や、Flask等のWEBアプリケーション開発または機械学習からになると思いますが、クラスを少しでも理解する事によってこれまで行ってきたライブラリ操作等もより理解が深まったのではないでしょうか。
当サイトではこれからもPythonに関する情報を取り扱っていきます。
是非覗いてあげてください。