2011-05-17 21 views
11

次のスクリプトを実行すると、両方のラムダがos.startfile()を同じファイル(junk.txt)で実行します。それぞれのラムダがラムダが作成されたときに設定された値 "f"の使用を期待しています。私が期待するようにこれを機能させる方法はありますか?関数が呼び出されたときにPythonのクロージャが期待どおりに動作しない

def main(): 
    files = [r'C:\_local\test.txt', r'C:\_local\junk.txt'] 
    funcs = [] 
    for f in files: 
     # create a new lambda and store the current `f` as default to `path` 
     funcs.append(lambda path=f: os.stat(path)) 
    print funcs 

    # calling the lambda without a parameter uses the default value 
    funcs[0]() 
    funcs[1]() 

そうでない場合fが見上げているので、あなたは、現在の(ループの後)の値を取得:

import os 


def main(): 
    files = [r'C:\_local\test.txt', r'C:\_local\junk.txt'] 
    funcs = [] 
    for f in files: 
     funcs.append(lambda: os.startfile(f)) 
    print funcs 
    funcs[0]() 
    funcs[1]() 


if __name__ == '__main__': 
    main() 
+0

と同様の[pythonでラムダ式のループを生成する](http://stackoverflow.com/questions/1841268/generating-functions-inside-loop-with-lambda-expression-in-python) – Rodrigue

答えて

22

一つの方法は、これを行うことです。

def make_statfunc(f): 
    return lambda: os.stat(f) 

for f in files: 
    # pass the current f to another function 
    funcs.append(make_statfunc(f)) 

あるいは(2.5+のpythonで):私はより良い好き

ウェイズ

from functools import partial 
for f in files: 
    # create a partially applied function 
    funcs.append(partial(os.stat, f)) 
+7

これは動作しますデフォルトの引数は関数定義時にバインドされているためです。 – delnan

+0

ああ、素晴らしい。生成されたlambdaは実際にPyQtのイベントハンドラとして使用されているので、入力パラメータを持つことはできません。現在はPython 2.4に固執していますので、functoolsを使用することはできません。別の機能 - 完璧に動作します。ありがとう。 –

+0

@Brendan、qtスロットを定義している場合は、デフォルトで入力パラメータを持つことができますか?また、2番目の解決策を使用する場合は、デコレータ「PyQt4.QtCore.pyqtSlot」を適用することもできます。 –

4

それは変数がクロージャの一部になったとき、それは変数自体だということを理解することが重要だと値は含まれていません。

これは、ループ内で作成されたすべてのクロージャが非常に同じ変数fを使用しており、ループの最後にループ内で最後に使用された値が含まれることを意味します。そのため、言語が定義されている方法の

しかし、これらの捕獲変数は、Python 2.xの中で「読み取り専用」です。それはglobal宣言していますしない限り、すべての割り当ては、ローカル変数1になります(Pythonの3.xのはへの書き込みを許可するようにnonlocalキーワードを追加外側スコープのローカル)。

ヨッヘンRitzelは、デフォルトのパラメータ値が関数の作成時に評価されているので、この変数捕捉を回避し、代わりに値のキャプチャを取得するための一般的なイディオムが

lambda f=f: os.startfile(f) 

を書くためにこの作品であり、fが彼の答えで述べたように外部変数ではなく、デフォルトとして必要な値を持つ関数パラメータです(このラムダは、パラメータのデフォルト値を持つ関数であり、それ以上のレキシカル変数を閉じることはありません)。

関連する問題