Java meets Python - 第6回 配列と別れる50の方法(3) ライフゲーム
よろずプログラマーのためのPython導入ガイド (8)
愛の十字架:隘路を切り開く
「無くて七癖…」と言われますが、頭では分かっていても(無意識に)身体が反応します。tryの十字架を背負いそうになったら、この話を思い出してください。
まず、生命体を単なる値ではなく、オブジェクトとして表現することから始めます。

class Life:
def __init__ (self, x, y):
self.x = x
self.y = y
self.present = False
self.future = False
self.neighbor = []
def __repr__(self):
s = StringBuffer()
s.append(self.xyString())
s.append(`self.present` + "->")
s.append(`self.future` + ":")
for e in self.neighbor:
s.append(e.xyString())
s.append(":" + `self.neighbors()`)
return `s`
def __str__(self):
return repr(self)
任意の生命体は、座標x/yの他に、現在presentと次世代futureの生死の状態を持つインスタンスと見なせます。ここでは、生命体の左上の隅をその座標値とします。インスタンスに固有の情報を文字列として出力すると、次のようになります。
>>> (4,3)False->False:(3,2)(4,2)(5,2)(3,3)(5,3)(3,4)(4,4)(5,4):0
この結果は、メソッド__str__で規定した文字列表現から得られます。
配列に値を保持させるのではなく、その対象を「オブジェクト」として実現します。生命体は、単なるbool型の値ではありません。自分が次世代で生存できるかは、生命体自身で判断します。つまり、オブジェクト自身が「思考」すると共に、周りの仲間とも相談するというわけです。
デザインパターン:Null Object
GoFのカタログにはない、古典的なパターンの一つにNull Objectがあります。今回はこのNull Objectを利用して、境界の外側を定義します。
class Life:
def xyString(self):
return "(%r,%r)"%(self.x, self.y)
def reverse(self):
self.present = not self.present
生命体には、2つのメソッドを定義します。メソッドxyStringは、座標を表す文字列をリターン値とします。生成した生命体の位置は不変です。メソッドreverseは、生命体の状態色(生存 Color.red/死滅 Color.white)を規定します。

先の連載第2回で紹介したNull Objectは、境界の外側を特殊な生命体と見なします。これは、すべてのオブジェクトを平等に扱いつつ、その個性を尊重するという管理手法に適います。Null Objectに関する広範な論議は、Smalltalkが参考になります。
インスタンスに固有のメソッド定義
Null = Life(0, 0) Null.xyString = lambda: "()" Null.reverse = lambda: None
境界外の生命体Nullには、2つのメソッドを再定義します。メソッドxyStringは、座標を表示する必要がないので、文字列 "()" をリターン値とします。メソッドreverseは、何もする必要がないので、その本体は空Noneとなっています。すると、Nullは、他の生命体と違う個性を発揮します。
Nullの実体は一つだけしか存在しませんが、あたかも境界外を取り囲むかのように図示してあります。条件式や例外処理など、煩雑で面倒な処理を一手に引き受けるNull Objectは、目立たず(逆に目立っては困る)頼もしい限りの存在です。まるで舞台に登場する黒子(存在しないものと見なされる)のように。
class Life:
def paintItem(self, g):
edge = self.Edge
x = self.x * edge
y = self.y * edge
g.setColor(self.fillColor())
g.fillRect(x, y, edge, edge)
g.setColor(Color.black)
g.drawRect(x, y, edge, edge)
def fillColor(self):
return (Color.white, Color.red)[self.present]
メソッドpaintItemは、生命体を描きます。背景を描くために、fillColorを再利用します。生命体が生存なら赤Color.redで、死滅なら白Color.whiteでそれぞれ表示します。
Nullを導入すると、配列の添字が範囲を超えたときの例外に対処するtry文が不要になるので、コードの見通しがよくなります。Nullの存在を確認するには、例えば、ウィンドウの大きさを変形させて、右/下の境界外をクリックします。すると、次のような情報が出力されます。
>>> ()False->False::0
この記事は参考になりましたか?
- よろずプログラマーのためのPython導入ガイド連載記事一覧
-
- Java meets Python - 第7回 ハリウッドの原則
- Java meets Python - 第6回 配列と別れる50の方法(3) ライフゲーム
- Java meets Python - 第5回 二分木と辞書
- この記事の著者
-
小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)
http://tamago-club.cocolog-nifty.com/「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたから楽ができるのと...
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
伊藤うさぎ(イトウ ウサギ)
ペンネームの「由来は」と言うと。苗字の方は、セミナー研修で同じチームになった、3人の合体ユニット名 [I:石塚, T:田川, O:尾沢] から来ています。名前の方は、同じ干支(卯:1987 年生)に因んだものです。既に2人は卒業して、残る1人がその名跡を継承しています。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
