2009-05-08 8 views
5

カレー化された関数のリストを作成しようとする試みがうまくいかないのはなぜですか?このpython関数のラムダ式はどうなっていますか?

def p(x, num): 
    print x, num 

def test(): 
    a = [] 
    for i in range(10): 
     a.append(lambda x: p (i, x)) 
    return a 

>>> myList = test() 
>>> test[0]('test') 
9 test 
>>> test[5]('test') 
9 test 
>>> test[9]('test') 
9 test 

ここでは何が起こっていますか?実際に私は上記の機能を行うことを期待し

機能は次のとおりです。

Pythonで
import functools 
def test2(): 
    a = [] 
    for i in range (10): 
     a.append(functools.partial(p, i)) 
    return a 


>>> a[0]('test') 
0 test 
>>> a[5]('test') 
5 test 
>>> a[9]('test') 
9 test 
+0

functools.partialを使用するソリューションがあるので、何が問題なのですか? –

+2

質問は、最初の方法はなぜ機能しないのですか? – David

答えて

12

、ループや枝で作成された変数がスコープされていません。 lambdaで作成しているすべての関数は、ループの最後の反復で9に設定された同じi変数への参照を持っています。

解決策は、関数を返す関数を作成して、イテレータ変数のスコープを決めることです。このため、functools.partial()のアプローチが有効です。例:

+0

どうもありがとう! – David

1

さてあなたも怠惰のための外側のラムダiにバインドすることができます。

def p(x, num): 
    print x, num 

def test(): 
    a = [] 
    for i in range(10): 
     a.append((lambda i :lambda x: p (i, x))(i)) 
    return a 
1

なぜこれが機能しないのか、私はいつも混乱していました。説明をありがとう、 'a paid nerd'。

for i in range(10): 
    a.append(lambda num, val_i=i: p (val_i, num)) 

注まだ効果的lambda 1つの変数の関数を作りながら、ループ中にiの瞬時値をキャプチャすることができますlambdaval_i=iデフォルト引数:私は個人的にこのソリューションを好みます。 (ところで:。pの定義と一致するnumにあなたのxを変更)私は好きそれより良い理由:

  1. それはオリジナルのアイデアに非常に近いとの正確な目的を新しい名前の関数を定義する必要がなくなりラムダは...

ちょうど検索を行なったし、そこに同じ問題のためのより詳細な説明を見つけた...

  • functoolsをインポート回避し、imbricatingラムダを回避:Scope of python lambda functions and their parameters

  • +0

    名前付き引数は、これがなぜ機能するのか、なぜオリジナルがしなかったのかです。ここで私はPythonでクロージャの探査を行っています:https://gist.github.com/maxcountryman/5035489 – maxcountryman

    関連する問題