初心者が一番わかりやすかったオブジェクト指向プログラミングの説明は、子供向けのマイクラ本だった。。
オブジェクト指向がわかりにくいのには理由があった
オブジェクト指向って初心者とっつきにくい概念で、わかりにくいですね。pythonなんか勉強しだすと、pythonはクラスの概念がわかるまでやれといわれるんですが、オブジェクトに関連するクラス、オブジェクト、インスタンス、インヘリテンスいろいろ出てきてこんがらがってしまう。。
また下手な参考書やネットの教材なんか読むと、数学の教科書の説明みたいな抽象的なことしか書いてなくて余計わからないんですね。オブジェクト指向がわからないのは世の参考書や教材の説明が今一つだからなんだと気づきました。
オブジェクト指向のクリアな説明とは子供向けの教科書で見つかった
そんな時一番クリアにな説明している参考書を偶然見つけたんです!
実は子供向けの(といっても中学生くらい)のマインクラフトをpythonで改造する(Minecraft moding)方法を書いたものです。
子供がマインクラフトに興味があるので、それを利用してプログラミングを教えられないかと本を探していたらみつかったのですが、中学生向けだけあってわかりやすく書かれているうえ、この本一冊やるとpythonの大体の機能がわかるという仕組みになっているんです!
最後の章がオブジェクト指向を扱っていて、思わず読んでしまいました!
オブジェクト指向の説明はズバリ!
変数と関数をひとまとめにしたクラスを作るプログラミングの手法です。
一言書かれています。ごちゃごちゃ説明してなくて一番すっきりした説明だなって思います。
それぞれのクラスは、同じ変数や関数を共有するオブジェクトを作るのに使います
関数がクラスの中に含まれている時、メソッドと呼ばれ、変数がクラスの中に含まれている時は属性と呼ばれます
と説明が続くのですが、これだとわかりにくいので、
ネコ(Cat)というクラスをつくってみることを考えてみる説明が絶妙でした。
ネコ(Cat)をpythonのクラスで定義してみよう
(飼い)ネコには、たとえば名前と体重という属性があるわけで、それをpythonのプログラム的に表現すると、
class Cat(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
っていう感じなります。
def __init__(self, name, weight):
の部分はクラスの初期設定をしています。またselfの記載はクラス内のどのメソッドにも共通して必要で、そのメソッドが属するクラスを指定するのに使います。それでこのクラスで指定されるオブジェクトCatには二つの属性nameとweightがあるわけです。
このCatのクラスを、Fluffという4.5kgのネコを定義するににつかうとすると
class Cat(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
fluff = Cat("Fluff", 4.5)
となりますが、もしFluffの体重属性を知りたくなったら、このクラスの記載を使って
class Cat(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
fluff = Cat("Fluff", 4.5)
print(fluff.owner)
と出力すればいいんですね。これでだいぶクラスがわかってきたんではないでしょうか?
次にメソッドなんですが、ネコの機能として、食べる、食べて寝るっていう二つを考えます。
食べる機能には、食材を変数としてとり、体重が0.05㎏増え、「食材を食べています」と出力します。
食べて寝る機能には食べる機能を参照したのち、「今寝ています」と出力します。
それを実際に実装すると
class Cat(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
def eat(self, food):
self.weight = self.weight + 0.05
print(self.name + " is eating " + food)
def eatAndSleep(self, food):
self.eat(food)
print(self.name + " is now sleeping...")
こんな風にすればいいんですね。
これだけみるとまだ?かもしれませんが、
class Cat(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
def eat(self, food):
self.weight = self.weight + 0.05
print(self.name + " is eating " + food)
def eatAndSleep(self, food):
self.eat(food)
print(self.name + " is now sleeping...")
fluff = Cat("Fluff", 4.5)
print(fluff.weight)
fluff.eat("tuna")
fluff.eatAndSleep("tuna")
print(fluff.weight)
出力を付けてあげるとわかりやすいです。
これ実際のpythonで動くので出力してみてください。
4.5
Fluff is eating tuna
Fluff is eating tuna
Fluff is now sleeping...
4.6
Fluffというネコが2回ツナを食べて昼寝して、体重が4.5から4.6kgになるのがわかると思います。
自分自身はこれまでクラスを使ったコードを見た時に今一つ意味がわからずどこから呼んでいったらわからなかったのですが、この説明をみて目からうろこでした!初心者でクラスを使ったオブジェクト指向のコードがとっつきにくいと思ったらまずはこのネコのコードを見るとよいと思います。
トリのクラスを定義してインヘリテンスを知ろう
また本編ではこの後トリというクラス(オブジェクト)を設け、鳴き声と飛行というメソッドをつくります。
このトリにはペンギンとパロットとというサブクラス(オリジナルのオブジェクトとは少し違うメソッドや属性をもっている=インスタンスがオリジナル(スーパークラス)とは少し異なる)をつくる。この少し違ったものを作るのにインヘリテンスという概念が重要になる。
ペンギンはトリのクラスに属するけど、違う鳴き声をし、泳ぐという新しいメソッドをもち、飛行メソッドは「飛べない」と出力する(オーバーライドにより書き換えている)。
パロットは色という属性を持つつが、メソッドはオリジナルのバードと同じ(これを継承(インヘリテンス)とよぶ)のように定義します。
実装は
class Bird(object):
def __init__(self, name, wingspan):
self.name = name
self.wingspan = wingspan
def birdcall(self):
print("chirp")
def fly(self):
print("flap")
class Penguin(Bird):
def swim(self):
print("swimming")
def birdcall(self):
print("sort of a quack")
def fly(self):
print("Penguins cannot fly :(")
class Parrot(Bird):
def __init__(self, name, wingspan, color):
self.name = name
self.wingspan = wingspan
self.color = color
gardenBird = Bird("Geoffrey", 12)
gardenBird.birdcall()
gardenBird.fly()
sarahThePenguin = Penguin("Sarah", 10)
sarahThePenguin.swim()
sarahThePenguin.fly()
sarahThePenguin.birdcall()
freddieTheParrot = Parrot("Freddie", 12, "blue")
print(freddieTheParrot.color)
freddieTheParrot.fly()
freddieTheParrot.birdcall()
という形です。出力は
chirp
flap
swimming
Penguins cannot fly :(
sort of a quack
blue
flap
chirp
といった風になりますね。これでサブクラスへのインスタンスの継承とその変更のイメージが付きやすいと思います。
あとこれに本来は実際のクラスをつかったプログラムがあるとわかりやすいのですが、本編では
from mcpi.minecraft import Minecraft
mc = Minecraft.create()
import time
class NamedBuilding(object):
def __init__(self, x, y, z, width, height, depth, name):
self.x = x
self.y = y
self.z = z
self.width = width
self.height = height
self.depth = depth
self.name = name
def build(self):
mc.setBlocks(self.x, self.y, self.z,
self.x + self.width, self.y + self.height, self.z + self.depth, 4)
mc.setBlocks(self.x + 1, self.y + 1, self.z + 1,
self.x + self.width - 1, self.y + self.height - 1, self.z + self.depth - 1, 0)
self.buildWindows()
self.buildDoor()
def clear(self):
mc.setBlocks(self.x, self.y, self.z,
self.x + self.width, self.y + self.height, self.z + self.depth, 0)
def getInfo(self):
return self.name + "'s location is at " + str(self.x) + ", " + str(self.y) + ", " + str(self.z)
def buildWindows(self):
mc.setBlock(self.x + (self.width / 4 * 3), self.y + 2, self.z, 0)
mc.setBlock(self.x + (self.width / 4), self.y + 2, self.z, 0)
def buildDoor(self):
mc.setBlocks(self.x + (self.width / 2), self.y + 1, self.z, self.x + (self.width / 2), self.y + 2, self.z, 0)
pos = mc.player.getTilePos()
x = pos.x
y = pos.y
z = pos.z
ghostCastle = NamedBuilding(x, y, z, 10, 16, 16, "Ghost Castle")
ghostCastle.build()
mc.postToChat(ghostCastle.getInfo())
time.sleep(30)
ghostCastle.clear()
のようなマインクラフト用のコードも学習するようになっていて、よくできています。もしマインクラフトのPC版をお持ちであれば、この本を取り寄せて読まれると、英語もわかりやすいので、すごく勉強になると思います。誰か日本語訳しても面白いかもしれませんね。Aidemyあたりでやったら子供向けの教育プログラムとして利用できるかもしない!
あとここでちょっと引用したコードは
にてダウンロードできます。興味のある方は是非ご覧ください。