2016-04-23 8 views
16

は、私は、Python 3.5.1に次のコードを試してみました与える:辞書の理解は間違った結果

>>> f = {x: (lambda y: x) for x in range(10)} 
>>> f[5](3) 
9 

これは5を返す必要があることそれは明らかです。私は他の価値がどこから来ているのか分からず、何も見つけることができませんでした。

これは参照に関連するもののようです - それは常に最後に割り当てられた機能であるf[9]の答えを返します。

ここでエラーとはどのようにして正しく動作するのですか?

答えて

14

Pythonスコープは語彙です。クロージャは、変数の実際のオブジェクト/値ではなく、変数の名前とスコープを参照します。

各ラムダが変数xをキャプチャしていない場合、の値はです。すべてのラムダ、その値はこのxを参照しますので、変数xが9にバインドされているループの終わりに

は、9

なぜ@ ChrisPの答えは動作します:

make_funcxの値が評価されるように強制されます( が関数に渡されるため)。したがって、ラムダはxの値で現在 で作成されており、上記のスコープの問題は回避します。

def make_func(x): 
    return lambda y: x 

f = {x: make_func(x) for x in range(10)} 
+7

代替略記は '= Fであろう{X:(ラムダyをX = X:X)の範囲内のxの(10)}'、関数のデフォルト引数が定義時にバインドされているので、それほど彼らは_name_ 'x'ではなく' x'の_value_を束縛します。 – ShadowRanger

+0

これは非常にばかな質問のように聞こえるかもしれませんが(私はラムダにあまり慣れていませんが)、make_func(x)はどのように機能しますか?私はf [5](3)が〜f = {5:make_func(5)}を意味すると考えることができます。だから、make_func(5)(3)は5とどのように等しいのですか? – Adib

+1

辞書の理解は、intの辞書キーを関数の値にします。 f [5]は、関数lambda y:xである5によってキーが付けられた辞書の値を返します。ラムダは渡されるもの(y)を無視し、常にxを返すことに注意してください。だから、ラムダは(上記の問題のために)5または9のどちらかを返すでしょう。 – gnicholas

6

次の作業をする必要があります:あなたのコード内

def make_func(x): 
    return lambda y: x 

f = {x: make_func(x) for x in range(10)} 

x9で最後x値を参照してしまいますが、私の中では、関数スコープでxを指します。