Pythonでのオブジェクトの作成と呼び出しについて解説します。実際にプログラムを書きながらオブジェクト指向への理解を深めていきましょう。
目次
クラスの定義
まずはクラスを定義してみましょう。次のように記述します。
1 2 3 4 | class クラス名: 変数名 = 値 def メソッド名( self , 引数): 処理 |
クラス名の先頭は大文字にします。
また、クラス内でメソッドを定義する際には必ずselfという引数をとります。このselfについての詳細はインスタンス変数の項で解説します。
では実際にRPGゲームのモンスタークラスを定義してみましょう。まずは引数を受け取ってそれを使ったメッセージを表示するメソッドだけを持つクラスを作ります。
1 2 3 | class Monster: def attack( self , name): print (name + "は100のダメージを与えた" ) |
次にこのクラスからオブジェクトを作ってメソッドを呼び出してみましょう。
作成したオブジェクトは変数に代入して再利用できるようにします。書き方は次の通りです。
1 2 | 変数名 = クラス名() # オブジェクトを作成して代入 変数名.メソッド名(引数) # オブジェクトのメソッドを呼び出し |
1行目ではクラスからオブジェクトを作成して変数に代入しています。
このようにPythonの変数には文字列や数値だけでなく、オブジェクトを代入することもできます。
変数にオブジェクトを代入しているので、2行目の記述でオブジェクトが持つメソッドを呼び出すことができます。
実際に先ほどのコードに追記してみましょう。
1 2 3 4 5 6 | class Monster: def attack( self , name): print (name + "は100のダメージを与えた" ) monster = Monster() monster.attack( "デス・ナイト" ) |
ではコードを実行してみましょう。
結果は次のようになります。
1 | デス・ナイトは100のダメージを与えた |
オブジェクトのメソッドに引数を渡してそれを使った処理を実行することができました。
ですが、これだけだとクラスにメソッドをまとめているだけなので関数を定義した方が簡単です。
そこで次はこのクラスに変数を追加する方法についてみていきましょう。
コンストラクタとインスタンス変数
オブジェクトに変数を持たせたい場合はクラスにコンストラクタを追加します。
コンストラクタとはオブジェクトを作成する際に最初に自動で呼ばれる特別なメソッドです。
Pythonでは__init__(initの前後にアンダーバー2つ)と記述します。
1 2 3 | class クラス名: # クラスを定義 def __init__( self , 引数): # コンストラクタを追加 self .変数名 = 引数 # インスタンス変数に引数を代入 |
オブジェクトが持つ変数に初期値を設定したい場合はこのようにコンストラクタを追加して、その引数を変数に代入します。
ここでメソッドの引数として設定するselfが活躍します。
Pythonではクラス内にあるメソッドの第一引数に、メソッドを呼ばれたオブジェクト自身が渡されます。そのためクラスの第一引数は「自身」を表すselfと決まっているのです。
この「self.変数名」をインスタンス変数と呼びます。
インスタンス変数はオブジェクトが持つ固有の変数のことで、ローカル変数が一度スコープを抜けてしまえば値が消えてしまうのに対し、インスタンス変数はオブジェクトが存在する限り値が保存されます。
では実際に先ほどのオブジェクトにインスタンス変数として名前と攻撃力を与えてみましょう。
1 2 3 4 5 6 7 8 9 | class Monster: def __init__( self , name, ad): # コンストラクタを追加 self .name = name # インスタンス変数に引数を代入 self .ad = ad # インスタンス変数に引数を代入 def attack( self ): print ( self .name + "は" + str ( self .ad) + "のダメージを与えた" ) death_knight = Monster( "デス・ナイト" , 100 ) # オブジェクト作成時に引数に渡す値を記述 death_knight.attack() # オブジェクトのメソッドを実行 |
せっかく固有の名前を変数として与えるので、代入する変数名もdeath_knightにしてみました。
実行結果は次のようになります。
1 | デス・ナイトは100のダメージを与えた |
ちゃんと実行されました。
表示は先ほどと同じですが、今回はインスタンス変数を定義したのでMonsterクラスという設計図には「名前と攻撃力という変数を持っている」ことと、「それらを使ってメッセージを表示する」ことが定義されていて、Monsterクラスからdeath_knightという固有の名前と攻撃力を持つオブジェクトが生成されています。
Monsterオブジェクトからもう1体モンスターを生成してみるとわかりやすいでしょう。
先ほどのコードに次のコードを追記します。
1 2 | hamusuke = Monster( "ハムスケ" , 30 ) hamusuke.attack() |
実行結果は次のようになります。
1 2 | デス・ナイトは100のダメージを与えた ハムスケは30のダメージを与えた |
Monsterクラスという設計図を既に定義してあるのでオブジェクトを生成する際に引数を渡してあげるだけで、固有の値とattackメソッドを持つhamusukeオブジェクトが生成できました。
このようにオブジェクト指向では、一度クラスを定義してしまえば共通の属性を持つオブジェクトをそれ以降何度でも簡単に作成することができます。
オブジェクトをループで処理
複数のオブジェクトをリストにまとめてループで処理することもできます。
例として先ほどのMonsterクラスから3匹のモンスターを生成してリストにまとめ、ループで呼び出してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Monster: def __init__( self , name, ad): self .name = name self .ad = ad def attack( self ): print ( self .name + "は" + str ( self .ad) + "のダメージを与えた" ) monsters = [] # monstersリストを定義 # リストの要素としてオブジェクトを追加 monsters.append(Monster( "デス・ナイト" , 100 )) monsters.append(Monster( "ハムスケ" , 30 )) monsters.append(Monster( "スケリトル・ドラゴン" , 50 )) for monster in monsters: # リストをループで処理 monster.attack() # attackメソッドを呼び出し |
先ほどは変数にオブジェクトを代入しましたが、同じようにリストにもオブジェクトを代入することができます。
そしてこのように、クラスが共通している複数のオブジェクトはまとめて同じメソッドで呼び出すことができます。
この場合は同じMonsterクラスから作ったオブジェクトをmonstersリストに代入し、ループ処理の中で共通のattackメソッドを使って呼び出しています。
実行結果は次のようになります。
1 2 3 | デス・ナイトは100のダメージを与えた ハムスケは30のダメージを与えた スケリトル・ドラゴンは50のダメージを与えた |
ちゃんと3匹のモンスターが順番に呼び出されて、それぞれの名前と攻撃力に応じたメッセージが表示できています。