2017-11-08 5 views
0

私はラムダをPythonで学んでいます。私は関数f = [f1, f2...]のリストを作成して、各関数fi(x)がリストxをとり、(x[i]-1)を返すようにする必要があります。この単純なラムダ関数がなぜ奇妙な出力を与えるのですか?

これはコーディングを試みた方法ですが、私は驚くべき結果を得ています。なぜ3枚のプリントがそれぞれ異なる結果をもたらすのか理解してください。最後の2つは私を完全に困惑させてしまった!

f = [(lambda x: x[i]-1) for i in range(5)] 
# I expect f to be [ (lambda x: x[0]-1), (lambda x: x[1]-1), ...] 

x = [1, 2, 3, 4, 5] 

print f[0](x), f[1](x), f[2](x) # output: 4 4 4 !! 
print [f[i](x) for i in range(5)] # output: [0, 1, 2, 3, 4] as expected 
print [f[k](x) for k in range(5)] # output: [4, 4, 4, 4, 4] wha?!!! 

編集:この質問はsuggested duplicateとはかなり異なります。リンクされた質問では、ユーザーが関数呼び出しの代わりに関数のリストを作成したという単純なエラーがありました。しかし、Tomasz Gandorの回答では、ここでいくつかの例を使って尋ねたのと同じ問題が議論されています。

+0

https://stackoverflow.com/questions/6076270/python-lambda-function-in-list-comprehensions – 101

+0

ちょっと好奇心から、なぜあなたは何かをコーディングしています..奇妙な?純粋な学問的関心?結局、Guidoはそれらを実装したことに後悔します:http://legacy.python.org/doc/essays/ppt/regrets/PythonRegrets。pdf – Arne

+0

でもPython 3では 'i'でも動作しません。 – Szabolcs

答えて

5

これはよくある問題です。あなたが探しているのは

f = [(lambda x, i=i: x[i]-1) for i in range(5)] 
z = [1,2,3,4,5] 
print f[0](z),f[1](z),f[2](z) 
0 1 2 

あなたのリストの内包がiに5つの機能、すべてのポイントを作成しています。ループの最後で、iは4に等しく、あなたはラムダ関数のローカル変数に、私の現在の値を割り当てる

4としてそのために関係なく、あなたが呼んでいるものラムダ、それは iをevalutesません。 オプションの引数でこれを行います。

ラムダevalutesは実行時にparamsします。 Pythonは、それはいくつかのより多くの光を当てるかもしれませんあなたはこのように何かを定義することができます:

>>> f = lambda x: x[i] - 1 
>>> l = [1, 2, 3, 4] 
>>> f(l) 

Traceback (most recent call last): 
    File "<pyshell#91>", line 1, in <module> 
    f(l) 
    File "<pyshell#89>", line 1, in <lambda> 
    f = lambda x: x[i] - 1 
IndexError: list index out of range 

アップデートを:コメントからの質問に答える、この例では、元の質問にはあまり関係しているが、助けより良い機能のparams評価が

myvar=1 

def f(myvar=myvar): 
    print myvar 

f() # prints 1 
f(2) # prints 2 
myvar = 5 
f() # prints 1 

あなたがfを宣言する前にmyvarを宣言しない場合、あなたはwoul起こるかを理解しますdはNameError: name 'myvar' is not definedになります。これは関数変数が 'コンパイル'時に評価されたためです。ラムダのの評価はランタイムですが、オプションの引数を指定するとすぐに実行されます(したがってi = i)。それはより多くの明確さを提供したいと思います:

+0

明確にするために、パラメータにその値と同じ名前を付けることを避けるために、別の名前でインデックスを定義する方が良い考えはありませんか?例:範囲(5)のiに対してf = [(λx、idx = i:x [idx] -1)] – Arne

+0

Pythonのスコープ規則は私にとっては直感的ではありません(C/C++の背景から来ています)。私の例では、私の範囲は最初の行に限られていると仮定していました。 –

+0

@ArneRecknagelラムダ定義以外のコードではそれ以上扱わないので、選択肢の問題です。どちらのオプションも十分明確です。 – Vinny

3

変数iは、グローバルスコープにあり、いずれかの関数を呼び出すと、まだ4です。あなたがi = 1を行う場合は、あなたの2つの異常出力が1 1 1[1 1 1 1 1]

になるだろう、私はこの作品が見つかりました:

g = lambda i: lambda x: x[i] - 1 
f = [ g(i) for i in range(5) ] # i missed here 
print [f[k]([1,2,3,4,5]) for k in range(5)] # [0, 1, 2, 3, 4] 

i今第二のラムダにスコープされます。

関連する問題