Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

Pythonでのクロージャは?

Perl のクロージャを読んでちょっと気になったので。
Pythonの場合、簡単な例でいくと

def func1(args):
    x = args
    def func2(y):
        return y+' :closureValue='+x
    return func2

a = func1('test')
print a(' closure')
a = func1('abc')
print a(' closure')
a = func1('efg')
print a(' closure')

実行結果は以下

 closure :closureValue=test
 closure :closureValue=abc
 closure :closureValue=efg

※でも古いPythonだと動きませんね・・・。
うーん、クロージャを使う利点としては

  1. immutable化
  2. 関数テンプレート化

が大きいかなあと思います。
Pythonの場合だと完全なカプセル化はできないので"immutable化"できるのは良いと思います。
(パッと見の話。きっと完全ではないんだろうけど)
例えばフレームワークを開発する側と使用する側がいた場合、開発する側がAPIを提供する際に意図しない動きをしないよう、クロージャを使用するってパターンがあるかも知れないですね。
(まあそれだけのために使うのもなんですが)
逆に使用する側は関数テンプレートとして使用するのはそこそこ重宝しそうです。
(ここでの使用する側は一般開発者、ドメインロジック作成側に近い)
使用用途はやはりコールバック関数が多いでしょうね。
似たようなパターンが出てきた場合、関数テンプレート化でリファクタリングできるケースも考えられるかもしれません。
Javaだとバカバカとクラス作ってやらなきゃいかんし正直めんどい気がするなあ。
(設計次第だけども)

で私的にですが結局、クロージャって
関数をファクトリーパターン、ビルダーパターンで作る
てことに集約されるのかなと。
関数の作成方法はファクトリー、あるいはビルダーのみが知ってると。
で属性は見えないように保持されてますよと。
(できた関数(返された関数)はストラテジー的に扱うのが一般的パターンかなあ)

ちなみにJythonでは上記文法はエラーです。
回避方法は多分あるんだけど、次回まで待て!
うくく。
追記
Javaではどうなるのさ?って話ですがやっておられる方がいました。
http://www.programmers-paradise.com/tdiary/?date=20060104
更に追記
昔ってこんな感じで書いていたんだっけ?
えー?こんなダサくないよなあ・・・・。うーん。
これならJythonでも動くけど。エレガントじゃないな、やっぱ。

def func1(args):
    x = args
    def func2(y,x=x):
        return y+' :closureValue='+x
    return func2

a = func1('test')
print a(' closure')
a = func1('abc')
print a(' closure')
a = func1('efg')
print a(' closure')