1. ホーム
  2. python

[解決済み] ラムダ関数とそのパラメータの範囲?

2022-10-31 21:46:09

質問

一連のGUIイベントに対して、ほとんど同じコールバック関数が必要です。関数は、どのイベントがそれを呼び出したかに応じてわずかに異なる動作をします。私には単純なケースのように見えますが、ラムダ関数のこの奇妙な動作を理解することはできません。

そこで、私は以下のような簡略化したコードを持っています。

def callback(msg):
    print msg

#creating a list of function handles with an iterator
funcList=[]
for m in ('do', 're', 'mi'):
    funcList.append(lambda: callback(m))
for f in funcList:
    f()

#create one at a time
funcList=[]
funcList.append(lambda: callback('do'))
funcList.append(lambda: callback('re'))
funcList.append(lambda: callback('mi'))
for f in funcList:
    f()

このコードの出力は

mi
mi
mi
do
re
mi

期待した。

do
re
mi
do
re
mi

イテレータを使うとなぜおかしくなるのか?

ディープコピーを使用してみました。

import copy
funcList=[]
for m in ('do', 're', 'mi'):
    funcList.append(lambda: callback(copy.deepcopy(m)))
for f in funcList:
    f()

しかし、これにも同じ問題があります。

どのように解決するのですか?

ここで問題となるのは m 変数(参照)が周囲のスコープから取得されていることです。 ラムダスコープに保持されるのはパラメータのみです。

これを解決するには、ラムダ用の別のスコープを作る必要があります。

def callback(msg):
    print msg

def callback_factory(m):
    return lambda: callback(m)

funcList=[]
for m in ('do', 're', 'mi'):
    funcList.append(callback_factory(m))
for f in funcList:
    f()

上の例では、lambdaは周囲のスコープを利用して m を見つけるが、今回は である。 callback_factory スコープが作成されます。 callback_factory の呼び出しごとに一度だけ作成されます。

または functools.partial :

from functools import partial

def callback(msg):
    print msg

funcList=[partial(callback, m) for m in ('do', 're', 'mi')]
for f in funcList:
    f()