[python] クロージャ

以前、Mayaのウィンドウからlambdaを使用して引数付きの関数呼び出しを行う、みたいなことを書いたんですが、問題発生。


例えば動的にUIを作成した時、作成する部分をループでまわしてたとします。
その際、コントローラにバインドした関数の引数に、ループのカウンタなりを与えていたとします。

それを呼び出すと、同じ値の引数で呼び出される。
例えば具体的にはこんな感じ。

items = ['a', 'b', 'c', 'd', 'e']
for item in items:
  mc.button(l=item, c=lambda *args: func(item))

def func(item):
  print(item)

これで作られたボタンを押すと、常にitems最後の要素であるeが出力されるのみ。
これはどうやら実際に関数が呼ばれた時点で引数が評価されるから、っぽい。
deepcopyとかも試してみたけど、どうやらそういうことではないらしい。

そこでひらめいたのが以前lambdaに関して書いたときに、hohehohe2さんから頂いたコメント。
そこに書いてあったキーワードがクロージャ。

ということでクロージャの検索を行いました。
リンク   

wikipedia先生によると、

クロージャ (Closure) は、プログラミング言語において引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決する関数のことである。

ということみたいです。

あれ、これまさに今やりたいことと一緒、、、

ということで、次はこんなコードで試してみます。

items = ['a', 'b', 'c', 'd', 'e']
for item in items:
  fnc = callFunc(item)
  mc.button(l=item, c=fnc)

def callFunc(item):
  def func(*args):
    print(item)
  return func

以前同じ問題で悩んだことのある僕にとってはかなり大きな突破口となりえる当問題。
ドキドキの実行結果は・・・

成功!!

押すボタンによってa, b, c, d, eと出力してくれる。
やったーーーーーーーーーーーーーーーー!!

クロージャ、これはすごい。
突破口へのきっかけを作っていただいたhohehohe2さんには多大な感謝です。

クロージャって概念は関数型言語から来てるものなんでしょうか。
Haskellの勉強は滞ってますが、また時間見つけて勉強したいですねー。

コメントを残す

メールアドレスが公開されることはありません。