関連 : JavaScriptでパイプ風処理をするライブラリを作った
Pythonの面白いモジュールpipeを見つけたのでご紹介:-)。PythonでInfix Syntax(挿入記法),「パイプ」のような処理を実現するためのモジュール。
pipやeasy_installでpipeをインストールしたあと,以下のように使う。
>>> from pipe import *
>>> [1, 2, 3, 4, 5] | add # 合計を計算, sum([1, 2, 3, 4, 5])と等価
15
>>> [5, 4, 3, 2, 1] | sort # 小さい順にソート,sorted([5, 4, 3, 2, 1])と等価
[1, 2, 3, 4, 5]
>>> [1, 2, 3, 4, 5] | where(lambda x: x % 2) | tail(2) | concat #奇数のみ抽出し文字列として連結
addやsortはpipeの提供する関数で,「Pipableな」関数。Pipableな関数は演算子「|」の後に付けて使える。
利点はいくつかある。まずネストが深い多段の関数呼び出しが分かりやすく記述できるようになる。
sum(select(where(take_while(fib(), lambda x: x < 1000000) lambda x: x % 2), lambda x: x * x))
を
fib() | take_while(lambda x: x < 1000000)
| where(lambda x: x % 2)
| select(lambda x: x * x)
| sum()
のように書けるようになる。
もう一つの利点。Pipableな関数は値を遅延評価するので,ジェネレータで作った無限リストのようなものも扱える。
例えばフィボナッチ数を生成するジェネレータ関数を定義する。
>>> def fib():
... x = 1
... yield 1
... y = 1
... yield 1
... while True:
... x = x + y
... yield x
... y = x + y
... yield y
この関数を使って,「400万以下の偶数のフィボナッチ数の総和を求めよ」という問題を解くとする。
関数呼び出しをネストして以下のように書くと,sum()にリストを渡す前のリスト内包表記で処理が帰ってこなくなる。
>>> sum([x for x in fib() if x < 4000000 and x % 2 == 0])
pipeを使うと次のように書ける。
>>> euler2 = fib() | where(lambda x: x % 2 == 0) | take_while(lambda x: x < 4000000) | add
>>> assert euler2 == 4613732
関数型言語っぽいことをPythonで実現できる,面白いモジュールだ。