Python環境でScala風リスト操作をできるようにするパッチを書いた
abst
こういう書き方ができるようになるパッチ書いた
[1, 2, 3, 4].map(_ * 10).reduce(_ + _)
motivation
かねてよりpythonのmap
,filter
,reduce
はうっとしくてかなわん、と思っていた。何より、 method chain にまったく向いていない。
例えば、Scalaでは以下の様なコード
val sum_evens = Seq(1, 2, 3, 4, 5).filter(_ % 2 == 0).map(_ * 10).fold(0)(_ + _)
これが、Pythonではこうなる
sum_evens = reduce(lambda x, y: x + y, map(lambda y: y * 10, filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5])))
つらい。
pythonic とか Scala 使えとかいうのは忘れる。unpythonicで結構なのでこれを何とかしたい。
patch for built-in types
Python は monkey patch のやりやすい言語だが、built-in typesに対しては普通にはできない。方法はあるはずと探しに探したところ、強制的にパッチする gist をみつけた。
コメントには以下のようにある。
# found this from Armin R. on Twitter, what a beautiful gem ;)
Python界隈では大変有名な Armin Ronacher 先生作らしい(結局オリジナルは見つけられなかった)。
これだ!というわけで、ざっくりまとめてgithubに上げた。
https://github.com/kogecoo/prototype.py
ネーミングは同僚より。
install
pipに上げたら怒られそうな内容なので上げてない。 cloneしてinstallする必要がある。
$ git clone https://github.com/kogecoo/prototype.py.git $ cd prototype.py $ python setup.py install
usage
先ほどのコードはこのように書けるようになる。
from prototype import itr itr.attach() [1, 2, 3, 4, 5].filter(lambda x%2 == 0).map(lambda x: x*10).reduce(lambda x, y: x+y)
さらに、Scala-like な lambdaを書けるようにする(fn.py)https://github.com/kachayev/fn.py を使えば、そこはもうScala World...
from prototype import itr from fn import _ itr.attach() [1, 2, 3, 4].map(_ * 10).reduce(_ + _) # 100
調子に乗って、Scalaの ParSeq 的なこともできるようにした。
from prototype import par from operator import add par.attach() def mult10(x): return x * 10 if __name__=='__main__': [[1, 2], [3, 4]].par().flatmap(mult10).reduce(add)
残念なことにmultiprocessingの制約があってlambdaは使えない。fn.pyも無理。 Pathosというライブラリがこれを解決しそうだけど、pipがダメなので気長に待とう。
最後に
やればやるほどScalaで書けよと自分で突っ込みを入れたくなった。