Python

クラス(class)とインスタンス(instance)のイメージ

Pythonにおけるクラス設定やインスタンス生成のところは、なかなか感覚がつかめなくて頭に入ってきません。

そこで、ドラクエのキャラクターを作ることでクラスとインスタンスを理解し、使えるようにしたいと思います。

クラスとインスタンス

まずはクラスとインスタンスの説明です。

「クラス」とは、プラスチックの人形

「クラス」とは、ドラクエの登場人物のもととなるものです。

お菓子のおまけについてくる、人間の形をしたプラスチックの人形です。

これに服のシールや帽子のシール、メガネやひげのシールをペタペタ貼ることで、色んなキャラクターを作ることができます。

鎧のシールと剣のシール、そして筋肉のシールと短髪の髪型のシールをつけたら「戦士(男)」になります。

青いローブのシールと十字架が書かれた帽子のシール、ロングヘアーの髪型のシールをつけたら「僧侶(女)」になります。

ピエロの表情のシールと縞々の服のシールをつければ「遊び人」になります。

「インスタンス」とは、最終的にできあがるキャラクター

戦士や僧侶、遊び人といった、最終的にできあがるキャラクターを「インスタンス」といいます。

そして、ペタペタ貼ったシールたちが「インスタンス変数」です。

「クラス」に「インスタンス変数」をインプットすると、それに応じた「インスタンス」が出来上がります。

実際に、ドラクエのキャラクターを作ってみる

実際にクラス、インスタンスを使って、ドラクエのキャラクターを作ってみたいと思います。

クラス名はCharacterとします。

前述の例では、インスタンス変数は服装やアクセサリのシールでした。

ここでは、名前、職業、レベル(LV)、ヒットポイント(HP)、マジックポイント(MP)をインスタンス変数とします。

まずは初期設定をする(def __init__)

class Character():
    def __init__(self, name, job, LV, HP, MP):
        self.name = name
        self.job = job
        self.LV = LV
        self.HP = HP
        self.MP = MP

まずは、1行目で「class Character():」として、Character()というクラスを作ります。クラス名の頭文字は大文字にするのが命名規則です。

2行目以降のところで、個性を出すためのインスタンス変数を定義していきます。

2行目は、「def __init__(self, 〇〇, △△, …)」の形を書きます。この赤字はクラスの初期設定をするための定型文のようなもので、〇〇、△△、…がインスタンス変数です。

なお、「__init__」はイニットと読みます。

3行目以降で、各インスタンス変数について「self.〇〇 = 〇〇」と書きます。これも定型文のようなものです。

これで、初期設定が終わりました。

※インスタンス変数は全て小文字にするのが命名規則ですが、ここでは見やすさ重視ということで大文字も使っています。

各キャラクターができることを設定する(def)

足元を調べるという機能をつけたい場合、下に次のコードを付け足します。

    def shiraberu(self):
        print('{}はあしもとをしらべた。
         なんと、かくしかいだんがみつかった!'.format(self.name))    

この機能をshiraberu()という関数名にしています。

コードに書いてあるように、shiraberu()のカッコ内には必ず「self」を入れます。

そして、関数の中身を書いていきます。

関数の中で使うコンスタンス変数は、selfをつけてself.〇〇とします。

キャラクターを作る(インスタンスを生成する)

いよいよ、個々のキャラクターを作っていきます。

「sarii」というキャラクターを作るとします。

名前は「さりい」、職業は「魔法使い」、レベルは15、HPは45、MPは80とします。

sarii = Character('さりい', '魔法使い', 15, 45, 80)

これで「sarii」が完成しました。さりいという名前のキャラクターです。

キャラクターに足元を調べさせる(関数の実行)

「sarii」に足元を調べさせてみます。

sarii.shiraberu()

さりいはあしもとをしらべた。なんと、かくしかいだんがみつかった!

「sarii」の名前がちゃんと入った状態で、shiraberu()が実行されることを確認できました。

もっと関数を増やしてみよう

キャラクターの動作にバラエティをもたせるため、さらに関数を追加します。

import pandas as pd

class  Character():
    def __init__(self, name, job, LV, HP, MP):
        self.name = name
        self.job = job
        self.LV = LV
        self.HP = HP
        self.MP = MP
        
    def shiraberu(self):
        print('{}はあしもとをしらべた。
        なんと、かくしかいだんがみつかった!'.format(self.name))    
    
    def status(self):
        display(pd.DataFrame([self.job, self.LV, self.HP, self.MP], 
         index=['職業', 'LV', 'HP', 'MP'], columns=[self.name]))
        
    def level_up(self):
        print('{}はレベルが{}になった!'.format(self.name, (self.LV +1)))
        print('LV: ' + str(self.LV) + '→' + str(self.LV + 1))
        self.LV = self.LV + 1
        
    def use_hyado(self):
        print('{}はヒャドをとなえた!'.format(self.name))
        print('MP : ' + str(self.MP) + '→' + str(self.MP - 10))
        self.MP = self.MP - 10
        
    def damaged_by_slime(self):
        print('スライムのこうげき!{}は3のダメージをうけた!'.format(self.name))        
        print('HP : ' + str(self.HP) + '→' + str(self.HP - 3))
        self.HP = self.HP - 3

追加した関数は以下4つです。

・各キャラクターのステータスを表示するstatus()関数
・レベルが上がるlevel_up()関数
・ヒャドを唱えるuse_hyado()関数
・スライムの攻撃を受けてダメージを食らうdamaged_by_slime()関数

status()関数でdataframeを使用するため、冒頭でPandasをインポートしています。

それでは、追加した関数を「sarii」に実行させてみます。

sarii.status()
sarii.level_up()

さりいはレベルが16になった!
LV: 15→16

sarii.use_hyado()

さりいはヒャドをとなえた!
MP : 80→70

sarii.damaged_by_slime()

スライムのこうげき!さりいは3のダメージをうけた!
HP : 45→42

ドラクエっぽくなってきました。

最後に、もう一度status()関数を実行してステータスを見てみます。

sarii.status()

上で実行したことがステータスに反映されていることを確認できました。

別のキャラクターをつくる

「takao」というキャラクター(インスタンス)も作ってみます。

takao = Character('たかお', '戦士', 14, 120, 0)

これで「takao」の完成です。

takao.status()

せっかく作ったので、「takao」のレベルを上げてみます。

takao.level_up()

たかおはレベルが15になった!
LV: 14→15

補足(結局、selfとは何だったのか?)

クラス、インスタンスがわかりにくい原因に、selfというのがあります。

一見、何のために存在しているのかわかりませんが、これがないとうまく動きません。

イメージはこんな感じです。selfとは「sarii」とか「takao」が入る変数です。

Character(self, name, job, LV, HP, MP)

Characterというプラスチック人形に、nameシール, jobシール, LVシール, HPシール, MPシールを貼ったものを、selfというキャラクターにしましょう、という意味です。

カッコ内に入っているものはすべて変数です。

ここに具体的な値を当てはめてみます。

「sarii」の例ですと、

Character(sarii, 'さりい', '魔法使い', 15, 45, 80)

Characterというプラスチック人形に、’さりい’、’魔法使い’、15、45、80を貼ったものを、sariiというキャラクターにしましょう。

「takao」の例ですと、

Character(takao, 'たかお', '戦士', 14, 120, 0)

Characterというプラスチック人形に、’たかお’、’戦士’、14、120、0を貼ったものを、takaoというキャラクターにしましょう。

となります。

このように、Character()の__init__で、インスタンスの原型にインスタンス変数を付与してインスタンスを生成しています。

class Character():
    def __init__(self, name, job, LV, HP, MP):
        self.name = name
        self.job = job
        self.LV = LV
        self.HP = HP
        self.MP = MP

 

それで、実際にインスタンスを作るときは、

Character(self, name, job, LV, HP, MP)

という形ではなく、

self = Character(name, job, LV, HP, MP)

という形になっています。