2009-07-10 10 views
14

ここでは何が起こっていますか?私は、関数のリストを作成しようとしている:これは私が何を期待Python Lambdaの問題

def f(a,b): 
    return a*b 

funcs = [] 

for i in range(0,10): 
    funcs.append(lambda x:f(i,x)) 

やっていません。

funcs[3](3) = 9 
funcs[0](5) = 0 

しかし、リスト内のすべての機能が同じように見える、と9に固定値を設定する:

funcs[3](3) = 27 
funcs[3](1) = 9 

funcs[2](6) = 54 

任意のアイデアを、私は、リストがこのように行動することを期待しますか?

答えて

18

ラムダが閉鎖されている正しいです....あなたはそれを与える引数は」上がりませんラムダが評価されるまで評価されることになる。その時、反復が終了したので、i = 9に関係なく。

あなたが探している行動は、あなたが何を考えに反して、各ラムダ、にバインドされている唯一のiがありますfunctools.partial

import functools 

def f(a,b): 
    return a*b 

funcs = [] 

for i in range(0,10): 
    funcs.append(functools.partial(f,i)) 
+0

functools.partial(f、i) – FogleBird

+0

私は同意する必要があります。部分的なアプリケーションはここに行く方法です。 –

+0

ここで、partial(f、i)はpartial(f、b = i)ではなくpartial(f、a = i)を表します。元の投稿と同じではありません。部分関数アプリケーション 'from right'(http://www.gossamer-threads.com/lists/python/dev/715103)は2回拒否されました。 – sunqiang

2

が何か良いPythonの関数と同様にi == 9

の最終値を考慮すると、定義されたスコープ内の変数の値を使用するようになるだろう。おそらくlambda: varname(それはそれが言語構成であるということです)は、値ではなく名前にバインドし、実行時にその名前を評価しますか?

と同様に

:私は私の答えの出見つけることに非常に興味があると思い

i = 9 
def foo(): 
    print i 

i = 10 
foo() 

はPythonで

10

で達成することができます。これはよくある間違いです。あなたが欲しいものを得るために

一つの方法は次のとおりです。

for i in range(0,10): 
    funcs.append(lambda x, i=i: f(i, x)) 

は今、あなたはそれぞれのラムダ閉鎖にデフォルトパラメータiを作成し、それをループ変数iの現在を結合しています。

13

ええ、通常の「スコープの問題」(実際にはバインディング - 後であなたが望む問題ですが、その名前でよく呼ばれます)。あなたはすでに "ファクトデフォルト"のi=iソリューションとfunctools.partialという2つのベストな答えを得ていますので、私は古典的な3つの "ファクトリーラムダ"の3つ目を与えています:

for i in range(0,10): 
    funcs.append((lambda i: lambda x: f(i, x))(i)) 

個人的には、funcsの関数が、1ではなく2つのパラメータで誤って呼び出される危険性がなければ、i=iといってもいいですが、ファクトリ関数のアプローチは、 1つのargを束縛する。

+2

私は前にこれを見たことがありません。ちょっとしたもの。 – ars

+0

@ars、実際に(Pythonで)ほとんどの場合の過剰なビットですが、Schemeで自然に何をするのでしょうか? –

+0

そうですね、私はそれが好きなケースをすぐに考えることはできませんが、それにもかかわらず楽しいコンストラクションです。 :-) – ars