SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

よろずプログラマーのためのPython導入ガイド

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)を規定します。

nullオブジェクト
nullオブジェクト

 先の連載第2回で紹介したNull Objectは、境界の外側を特殊な生命体と見なします。これは、すべてのオブジェクトを平等に扱いつつ、その個性を尊重するという管理手法に適います。Null Objectに関する広範な論議は、Smalltalkが参考になります。

インスタンスに固有のメソッド定義

Null = Life(0, 0)
Null.xyString = lambda: "()"
Null.reverse  = lambda: None

 境界外の生命体Nullには、2つのメソッドを再定義します。メソッドxyStringは、座標を表示する必要がないので、文字列 "()" をリターン値とします。メソッドreverseは、何もする必要がないので、その本体は空Noneとなっています。すると、Nullは、他の生命体と違う個性を発揮します。

【付記】
 先に示した図はNull Objectの概念を表わしたもので、実際はsole instanceとして実現されます。そのため、インスタンス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導入ガイド連載記事一覧

もっと読む

この記事の著者

小泉ひよ子とタマゴ倶楽部(コイズミヒヨコトタマゴクラブ)

http://tamago-club.cocolog-nifty.com/「楽しくなければ仕事じゃない」が私たちのモットー。99%の苦悩の連続も、1%の成功に報われます。だからこそ、この仕事が楽しくて仕方がないのです。楽をするための努力なら惜しみません。何もせず楽をしているのと、努力をしたから楽ができるのと...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

伊藤うさぎ(イトウ ウサギ)

ペンネームの「由来は」と言うと。苗字の方は、セミナー研修で同じチームになった、3人の合体ユニット名 [I:石塚, T:田川, O:尾沢] から来ています。名前の方は、同じ干支(卯:1987 年生)に因んだものです。既に2人は卒業して、残る1人がその名跡を継承しています。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2252 2008/06/13 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー