【Python】クラスを継承しオーバーライドを使いこなそう【簡単なゲームを作る】

ケンケン
クラスって引き継ぐことができるって知ってる?

 

コタロウ
知らないです。クラスを引き継ぐといいことあるの?
ケンケン
引き継いだ元のクラスのメソッドを書き換えて使ったり、プログラムをすっきり書くことができるんだ!
コタロウ
それは便利かも!教えて!
ケンケン
了解!それじゃいってみよう!

クラスの復習

前回はクラスの作り方の基本をお伝えしました。

クラス復習記事

ケンケン みんなはクラスって知ってる? コタロウ 知ってます!僕らはケンケンクラスのメンバーです! ぺんぺん そうだね! ケンケン そのクラスとは違うんだな。。。 […]

 

クラスを作成する際の書式やインスタンスの定義についてなど勉強しましたが、

プログラミング全体の流れを意識する良い機会になるのでしっかり復習しておいてくださいね。

 

さて、今回から簡単なゲームを作っていこうと思います。

内容は、出現した動物と交渉して交渉次第で仲間になってもらうゲームです。

クラスとオリジナルのメソッドをたくさん作っていくので勉強になると思いますよ。

まずは、クラスの継承からご紹介します。

 

クラスの継承とは?

Pythonではあるクラスの内容を引き継いだ他のクラスを作成することができます。

このことを「継承」といいます。

継承の基本

例えば、クラスAの内容を引き継いだクラスBがあったとするとそれは、

「クラスBがクラスAを継承している」といいます。

そして、このときのクラスAをスーパークラス、クラスBをサブクラスと呼びます。

継承の書式

▶クラスの継承の書式

class クラス名(継承元クラス名)

  メソッド等クラスの内容

継承の仕方は簡単です。

Animalクラスを引き継いだPenguinクラスを作りたいのなら

「class Penguin(Animal):」とすればOKです。

これで、クラスを継承できるのですが、

クラスを引き継ぐことに何の意味があるのだろうと疑問になりませんか。

引き継がなくても元のクラスからメソッド等を実行すれば問題ないように思いますよね。

 

継承のすばらしいポイントは、

サブクラスを作ることでスーパークラスの機能を書き換えることができる、ということなのです。

面白そうですね。ちなみに機能を書き換えることをオーバーライドと呼んでいます。

 

オーバーライドを実践してみよう

それでは、早速クラスの継承の醍醐味といえるオーバーライドを具体的に実践してみましょう。

まず、やりたいことをまとめます。

動物を仲間にするゲームを作る予定ですが、動物と交渉をするバトル風の仕組みにしたいと思います。

主人公が交渉を開始するとランダムで動物の反応が変わります。

その動物の対応がポイントとなり主人公側と動物側に振り分けられます。

ポイントが一定以上になれば動物が仲間になり、ポイントが一定以下になったら動物が逃げてしまうことにします。

その前提で、動物の反応の部分を以下の手順でオーバーライドを使ってプログラムしていきたいと思います。

 

▶オーバーライドとプログラム実行の手順

  1. スーパークラスの作成(Friendクラス)
  2. サブクラスの作成(GoodFriendクラス、DrawFriendクラス、BadFriendクラス、BestFriendクラス、)
  3. モジュール単体でプログラムを実行できるテストコードを書く

まず、スーパークラスで特定名のメソッドを作成しておいて、

それをサブクラスでオーバーライドしメソッドを再定義すると、同じメソッド名で複数の処理を実行できます。

では、実際にどのようになるか見ていきましょう。

 

「Friend.py」というファイルを作成して以下のようにコードを書いていきましょう。

まずは、スーパークラスを作ります。

スーパークラスを作る

▶Friendクラスを定義(Friend.py)

class Friend:
    def friend(self, point):
        return ''

Friendクラスの中に、friendメソッドを作成しています。

pointパラメーターはゲーム内で変動する動物の反応ポイントを格納するものですが、

オーバーライドを前提としているため処理内容は書かずにreturnで返される値も「’ ‘」で空欄としています。

 

クラスの作成方法がよく分からない方は以下の記事をご覧ください。

クラスの作り方

ケンケン みんなはクラスって知ってる? コタロウ 知ってます!僕らはケンケンクラスのメンバーです! ぺんぺん そうだね! ケンケン そのクラスとは違うんだな。。。 […]

主人公のポイントをプラスするサブクラス(GoodFriendクラス)

次はサブクラスを作成していきます。

ひとつめは、動物との交渉がうまくいったときにポイントが加算されるクラスです。

まずは、コードをご覧ください。

▶GoodFriendクラスを定義(Friend.py)

class GoodFriend(Friend):
    def friend(self, point):
        return['動物はよろこんでいる!', point]

1行目でFriendクラスを継承しています。

2行目以降でfriendメソッドをオーバーライドしています。

3行目で文字列とpointパラメータをリストとした戻り値を返すように設定しています。

リスト復習記事

みなさん、こんにちはケンケンです。   Pythonの基本事項をお伝えしています。 今回は、リストとタプルについてお話しします。 データをまとめておいておく大きな箱のようなものです。 これをうまく使い[…]

 

交渉が成功した場合なので主人公側にプラスポイント、動物側にマイナスポイントとなるようにします。

 

ポイント変動なしのサブクラス(DrawFriendクラス)

交渉したけどうまくいかずに引き分けになった場合のサブクラスを作成します。

ポイントの変動がないため、メソッド内でpointパラメータに0を格納して、そのまま戻り値として返します。

 

▶DrawFriendクラスを定義(Friend.py)

class DrawFriend(Friend):
    def friend(self, point):
        point = 0
        return['動物は考えている', point]

friendメソッドが受け取ったpointパラメータの値をすぐに0に置き換えて返しています。

主人公のポイントをマイナスするサブクラス(BadFriendクラス)

交渉が失敗したときに主人公側のポイントがマイナスするサブクラスを作成します。

このクラスのメソッドが受け取ったpointパラメーターを反転させてしまえばマイナスの値にすることが可能です。

▶BadFriendクラスを定義(Friend.py)

class BadFriend(Friend):
    def friend(self, point):
        return['動物は怒っている', -point]

 

一発で交渉成功のサブクラス(BestFriendクラス)

RPGでいうところの会心の一撃も設定しておきましょう。

▶BestFriendクラスを定義(Friend.py)

class BestFriend(Friend):
    def friend(self, point):
        point = 20
        return['動物は心打たれた', point]

DrawFriendクラスのときと考え方は一緒でpointパラメータを20に置き換えているだけです。

 

モジュール内で実行してみよう

Friendモジュールの作成は以上なのですが、コードがちゃんと書けているか心配ですね。

モジュール単体で実行する方法があるので以下のようにFriend.pyを書ききってください。

▶Friend.pyの全容

class Friend:
    def friend(self, point):
        return ''

class GoodFriend(Friend):
    def friend(self, point):
        return['動物はよろこんでいる!', point]

class DrawFriend(Friend):
    def friend(self, point):
        point = 0
        return['動物は考えている', point]

class BadFriend(Friend):
    def friend(self, point):
        return['動物は怒っている', -point]

class BestFriend(Friend):
    def friend(self, point):
        point = 20
        return['動物は心打たれた', point]
    
#====================================================
# 実行
#====================================================
if __name__ == '__main__':

    point = 2#とりあえず仮の数値を入力
    partner = GoodFriend()
    res = partner.friend(point)
    print(res)

    partner = DrawFriend()
    res = partner.friend(point)
    print(res)

    partner = BadFriend()
    res = partner.friend(point)
    print(res)

    partner = BestFriend()
    res = partner.friend(point)
    print(res)

 

if __name__ == ‘__main__’:って何?

if __name__ == ‘__main__’:という条件式がありますね。

なんだか怪しい呪文のようですが、内容は簡単です。

この条件式以下は、Friendモジュールを直接実行したときだけ読み取ってね、という意味です。

というのも、このFriendモジュールはたくさんのクラスで構成されています。

つまり、他のモジュールから呼び出されることを前提としたプログラムファイルな訳です。

ということは、呼び出されたときにすべてが実行されてしまうとめちゃくちゃになってしまいます。

それを「if __name__ == ‘__main__’:」という呪文で防いでいるわけです。

モジュール内のコードが正しく書けているかテストしたい場合に有効なので覚えておくといいでしょう。

 

条件式以下は特に難しくないと思います。

各サブクラスをオブジェクト化してfriendメソッドを実行しています。

じっくりコードを読み込んでみてください。

 

さあ、それではコードを実行してみましょう。

まとめ

いかがでしたか?

クラスの継承とオーバーライドについて勉強してきましたが、

みなさんちょっと疑問はありませんか。

別に継承とかオーバーライドとか使わなくても単純に4つのメソッドを作ればそれでいいのでは?と思いませんか。

その通りなんですが、実は今回のようにクラスを分けておくとメソッドを呼び分けることが簡単にできるのです。

次回は、メソッドを呼び分ける方法をご紹介しますのでお楽しみに!

それでは、また次回お会いしましょう。

次回記事

ケンケン 前回はサブクラスの作り方を学んだね ミケ はーい! ケンケン 今回は、サブクラスをどのタイミングで実行するか決めるプログラムを書いていくよ ミケ どうするんです[…]


 

ケンケン
継承とオーバーライドについて分かったかな?
コタロウ
なんとなくかな・・・
ケンケン
そうだね、はっきり全体を理解するのはまだ難しいかもね
ケロ
僕は理解できたよ!
ケンケン
ケロはすごいな!
ケロ
組織内では僕はサブクラスだからたくさんの仕事を引き継ぐことになるんだ。。。そういうことでしょ?
ケンケン
そ、そうかな(-_-;)
コタロウ
ケロは大丈夫だよ!自分の仕事を勝手にオーバーライドして毎日定時だもんね!
ケロ
ばれたケロ!