クラスとオブジェクト

目的

これまでにオブジェクトという言葉を使って様々なことを説明した.オブジェクトとはクラスから生成されるものであり,クラスはオブジェクトの型(設計図)のようなものである.ここでは,クラスの定義の仕方とオブジェクトの作り方・使い方を学ぶ.

説明

クラスの定義

オブジェクトはデータを保持し,そのデータに対して様々な処理をすることができるメソッドから成っていた.ここでは,2つの数値データを保持し,それらを加算・減算するメソッドを持つオブジェクトを作ることを通して,クラスの定義とオブジェクトの生成方法について説明する.

クラスの定義とオブジェクトの生成

ここでは2つのデータを処理する2項演算(Binary Operation)のクラスを定義する.例えば,以下の1行目のように,「class」の後にクラス名「BinaryOperation」を,その後に「:」を記述し,2,3行目のようにインデントを下げてクラス内容を記述する.

次に,7行目のように記述すると,定義されたBinaryOperationクラスのオブジェクトを生成し,オブジェクトに「binary_operation」という名前をつけることができる.BinaryOperationクラスのオブジェクトが生成されると,「__init__」という名前の初期化をするためのメソッドが呼び出される決まりとなっており,この例では3行目で「initialize」という文字列が表示されるようにしている.__init__メソッドの引数selfはオブジェクト自身を表しており,オブジェクト内のデータやメソッドを参照するときに使用される.また,オブジェクトが生成されるときに呼び出されるメソッドをコンストラクタと呼ぶ.

オブジェクトにデータを渡す

2つの数値データを処理する2項演算を行うために,オブジェクトに2つの数値データ(オペランド)を渡す必要がある.例えば,以下のように記述すると,コンストラクタによりオブジェクトを生成するときにオペランドを渡すことができる.

2行目のように,__init__メソッドの引数selfの後ろにカンマで区切ってoperand0, operand1という名前の引数を定義する.8行目のように,コンストラクタでオブジェクトを生成するときに,1と2という整数値をオブジェクトに渡すことができる.この例では,3,4行目で受け取った整数値を表示している.

オブジェクト内にデータを保存する

オブジェクト内にデータが保存されていれば,以下の9,10行目のように,オブジェクト名「binary_operation」の後に「.」を,その後に変数名を指定すると,オブジェクト内のデータが参照できる.

この例では,以下のようにエラーメッセージが表示され,うまく動作しないことがわかる.これはオブジェクトにデータは渡っているが,オブジェクト内にデータが保存されていないためである.

__init__メソッドの第1引数selfはオブジェクト自身を表すものであった.オブジェクト内に受け取ったデータを保存するには,以下のように記述すれば良い.

5,6行目で,__init__メソッドに引数として渡されたoperan0, operan1の値をオブジェクト内のoperand0とoperand1という名前の変数に保存している.このようにすれば,以下のように,オブジェクト内のデータを参照することができる.

加算するメソッドの定義と呼び出し

次に,オブジェクト内に保存された2つの値を加算し,結果を返すメソッドを定義してみよう.メソッドの定義の仕方は関数と同じである.異なるのは,メソッドはオブジェクト自身が保持しているデータに対する処理をすることになるため,第1引数としてオブジェクト自身を表すselfを記述することである.例えば以下の6,7行目のようにオブジェクトに保存されているオペランドの値を加算した結果を返すメソッドを定義し,14行目のようにメソッドを呼び出すと

オブジェクトに保存されている2つの値を加算した結果を取得し,表示することができる.

減算するメソッドの定義と呼び出し

さらに,減算を行うメソッドを追加するには以下のように記述すればよい.

複数のオブジェクトを生成する

クラスはオブジェクトの型(設計図)であるため,一度クラスを定義すれば,オブジェクトはいくつでも生成できる.例えば,同じBinaryOperationクラスからオペランドの数値を変えて2つのオブジェクトbinary_operation12とbinary_operation34を生成し,加減算を行うには,以下のように記述すればよい.

クラスの継承

ここでは,クラスの継承について説明する.クラスは継承することができ,継承されたクラスをスーパークラス,継承したクラスをサブクラスと呼ぶ.一般的には,スーパークラスは抽象度が高く,サブクラスは具体的なものになる.ここでは,RPGゲームにおけるキャラクタとして,勇者と賢者をクラスにより表現することを例にクラスの継承を説明する.

スーパークラス(キャラクタクラス)

オブジェクトはデータと機能(メソッド)をまとめたものであった.勇者と賢者に共通のデータと機能として,例えば以下のものを実装することにする.

  • データ
    • レベル
  • 機能
    • 現在のレベルを参照する
    • レベルアップする
    • 歩く

これらのデータと機能をもつCharacterクラスを定義すると,例えば以下のようになる.

この例では,Characterクラスのオブジェクトを生成すると,レベルが1に初期化されるようにしている.get_levelメソッドを呼び出すと,現在のレベルを参照することができ,levels_upメソッドを呼び出すと,引数で指定した値だけレベルが上がるようにしている.また,walksメソッドを呼び出すと「walks」という文字列が表示されるようにしている.

サブクラス0(勇者クラス)

勇者はキャラクタの一種であり,Characterクラスのデータと機能は全て実装したい.また,勇者は必ず剣を持っており,何かと戦うという機能があるとし,勇者特有のデータと機能として以下のものを実装することにする.

  • データ
    • 剣の名前
  • 機能
    • 剣の名前を参照する
    • 何かと戦う

このような場合,Characterクラスを継承すれば,スーパークラスであるCharacterクラスのデータと機能はそのまま使用できる.また,勇者特有のデータと機能はサブクラスで定義すればよい.

Characterクラスを継承したHeroクラスを定義するには,15行目のように記述すればよい.勇者は必ず剣を持っているとし,28行目のようにコンストラクタで剣の名前を指定するようにしている.そのため,16行目の__init__メソッドでは剣の名前を受け取るための引数が追加されている.17行目は,スーパークラスであるCharacterクラスの__init__メソッドを呼び出し,レベルを1に設定している.18行目でオブジェクト内に剣の名前を保存している.このようにすることで,レベルと剣の名前をデータとして保持するオブジェクトを生成している.20,21行目で剣の名前を取得するメソッドを定義し,33行目で呼び出している.また,23,24行目で引数で指定した何かと戦うメソッドを定義し,34行目で呼び出している.29行目から32行目はスーパークラスであるCharacterクラスのメソッドを呼び出しており,それらも正しく動作していることが確認できる.

サブクラス1(賢者クラス)

次に,賢者クラスも勇者クラスと同様にCharacterクラスを継承して定義しよう.賢者は必ず杖を持っており,呪文を唱えるという機能があるとし,賢者特有のデータと機能として以下のものを実装することにする.

  • データ
    • 杖の名前
  • 機能
    • 杖の名前を参照する
    • 呪文を唱える

27-36行目でSageクラスを定義し,__init__メソッドでオブジェクト内にレベルと杖の名前を保存し,杖の名前を取得するメソッド,引数で指定した呪文を唱えるメソッドを定義している.49行目で杖の名前を指定して賢者オブジェクトを生成し,54行目と55行目で定義したメソッドを呼び出している.

課題

課題0

2つの数値データを内部に保持し,加算を行うメソッドを持つクラスを定義し,オブジェクトを生成し,加算せよ.

課題1

2つの数値データを内部に保持し,加算と減算を行うメソッドを持つクラスを定義し,オブジェクトを生成し,加算と減算をせよ.

課題2

2つの数値データを内部に保持し,加算・減算・乗算を行うメソッドを持つクラスを定義し,オブジェクトを生成し,加算・減算・乗算をせよ.

課題3

2つの数値データを内部に保持し,加算・減算・乗算・除算を行うメソッドを持つクラスを定義し,オブジェクトを生成し,加算・減算・乗算・除算をせよ.

課題4

2つのbool型のデータを内部に保持し,論理積を行うメソッドを持つクラスを定義し,オブジェクトを生成し,論理積を求めよ.

課題5

2つのbool型のデータを内部に保持し,論理積と論理和を行うメソッドを持つクラスを定義し,オブジェクトを生成し,論理積と論理和を求めよ.

課題6

レベルを内部に保持し,レベルを参照する機能,レベルアップする機能,歩く機能を持つCharacterクラスを定義し,オブジェクトを生成し,各機能を使用せよ.

課題7

課題6のCharacterクラスを継承した勇者クラスを定義し,勇者特有のデータと機能を追加したクラスを定義し,オブジェクトを生成し,各機能を使用せよ.

課題8

課題6のCharacterクラスを継承した賢者クラスを定義し,賢者特有のデータと機能を追加したクラスを定義し,オブジェクトを生成し,各機能を使用せよ.

課題9

課題6のCharacterクラスを継承した魔法使いクラスを定義し,魔法使い特有のデータと機能を追加したクラスを定義し,オブジェクトを生成し,各機能を使用せよ.