for と別れる50の方法《05》クロージャー
Python.use(better) # OOP への道 《Python3.1, Jython2.5.0, IronPython2.6.x》
クロージャー
《著》真樹育未・後藤いるか・小粒ちゃん《監修》小泉ひよ子とタマゴ倶楽部
第0版♪1988/10/12 ● 第1版♪1993/05/23 ● 第2版♪2003/05/25
》移動中です《
■ 概要
for 文はいくつかの問題を抱え、OOP を実践するときの「障害」になります。
伝統的なC言語風の for 文や悪名高い switch 文、配列の呪縛から解かれ、オブジェクト指向プログラミング〔OOP〕の醍醐味を堪能するための準備を行います。
※ JPython1.1/Jython2.2 で作成した例題を、Python3.1 で再構成しました。
■ 関連記事
- Java プログラマーのための Python 導入ガイド
- 例題で学ぶ Jython/Swing デザインパターン《Jython2.5》改訂版
- ゲームに学ぶ Jython/Swing フレームワーク《Jython2.5》改訂版
- IronPython で学ぶ WPF プログラミングの世界《IronPython2.6》改訂版
何が問題か
OOP の「障害」になる for 文の問題点を明らかにするために、K&R を離れて、別の事例を紹介します。
《Note》Python にも for 文はあります。しかし、これはC言語風の for 文とは「異質」のものです。C言語における while/for の違いを同義語とするなら、Python の for は、同音異義語(似て非なるもの)のようなものです。
クロージャーを導入する
以下の事例に共通する s は、次のようなものです。
>>> s = LinkedList("ABCDE")
■ collect 操作
>>> # [e.lower() for e in s] >>> s.collect(lambda e: e.lower()) ['a', 'b', 'c', 'd', 'e'] >>> # [ord(e) for e in s] >>> s.collect(ord) [65, 66, 67, 68, 69] >>> # {e: ord(e) for e in s} >>> dict(s.collect(lambda e: (e, ord(e)))) {'A': 65, 'C': 67, 'B': 66, 'E': 69, 'D': 68}
■ select 操作
>>> # [e for e in s if ord(e)%3] >>> s.select(lambda e: ord(e)%3) ['A', 'C', 'D'] def isVowel(e): return e in "AEIOU" >>> s.select(isVowel) ['A', 'E']
■ detect 操作
>>> s.detect(lambda e: not ord(e)%3)
'B'
■ inject 操作
>>> s.inject(lambda s, e: e+s, "") 'EDCBA' def reverse(s, e): return e+s >>> s.inject(reverse, "") 'EDCBA' def update(m, e): m[e] = ord(e); return m >>> s.inject(update, {}) {'A': 65, 'C': 67, 'B': 66, 'E': 69, 'D': 68}
《Note》単純な collect/select 操作なら、内包を使って簡潔に表現できます。しかし、複雑な処理を必要としたり、detect/inject 操作になると、内包では断念せざるを得ません。
抽象操作を実現する
class LinkedList(Collection): def do(self, f): for e in self: f(e) def collect(self, f): return [f(e) for e in self] def select(self, f): return [e for e in self if f(e)] def detect(self, f): for e in self: if f(e): return e def inject(self, f, v): s = v for e in self: s = f(s, e) return s
。
def __repr__(self):
s = self.collect(self)
return "%s(%s)"%(self.__class__.__name__,",".join(s))
特殊 __repr__ メソッドは、collect 操作を使って簡潔に表現できます。
Tips:
》作業中です《
Last updated♪2009/07/06