2017-06-06 37 views
0

これはなぜ機能しないのですか?ループ内で関数を定義する方法

u = {} 
for me in ['foo', 'bar']: 
    def callback(): 
     return 'I am %s' % me 
    u[me] = callback 

私が手出力は次のようになります。

>>> u['foo']() 
'I am bar' 

callbackは、最新の繰り返しで一度定義されているようです。

EDIT

kawadhiya21によって提案されているように、クラスのアプローチがうまくいく:

class CallbackFactory(): 
    def __init__(self, me): 
     self.me = me 

    def __call__(self): 
     return 'I am %s' % self.me 

u = {} 
for me in ['foo', 'bar']: 

    u[me] = CallbackFactory(me) 

しかし、それははるかに複雑前者のアプローチを超えています。

+0

「u [me] = callback()」を試してみましょう。 – asongtoruin

+0

あなたはtypes.FunctionTypeがあなたを助けることができると思いますか? – Ptank

+1

クラスを作成する必要はありません。ちょうどPythonのクロージャーがレキシカルスコープでlate-bindingの振る舞いであることを理解してください。 –

答えて

5

すべての関数が同じ変数meを参照しています。関数を呼び出そうとすると、meの値は'bar'になります。これは、ループが終了したときの値なのでです。

meに関数の定義ごとに異なる値を使用させたい場合は、各関数に変数の独自のコピーが必要です。

u = {} 
for me in ['foo', 'bar']: 
    u[me] = lambda me_copy=me: 'I am %s'%me_copy 

あるいは

u = { me: (lambda me_copy=me: 'I am %s'%me_copy) for me in ('foo', 'bar') } 
0

ループ内で毎回callback()を再定義しています。だから最新のバージョンが動作します。クラスベースのアプローチを使うべきだと思います。

+2

これは正しくありません。 'u ['foo']'と 'u ['bar']'は同じ関数ハンドルではありません。 – acdr

2

まずオフ、あなたの例では、u['foo']は全く文字列を返すべきではありません、しかし:あなたが望む場合は、あなたがそれを短くすることができ

u = {} 
for me in ['foo', 'bar']: 
    def callback(me_copy=me): 
     return 'I am %s' % me_copy 
    u[me] = callback 

関数ハンドル。 :)編集:この文はもはや関連性がありません。

第2に、関数callbackは、外側スコープからmeを使用します。外側のスコープ内でこの値(ループによってあなたの場合)を変更すると、関数の出力も変更されます。

この問題を解決するには、meを関数の独自のスコープの一部にする必要があります。

def callback(int_me=me): 
    return 'I am %s' % int_me 
+0

私の間違いは、この例では '()'を忘れてしまった – nowox

0

出力の束を単に保存するのではなく、コールバックのファミリを定義しますか?

def make_callback(param): 
    def callback(): 
     return 'I am %s' % param 
    return callback 

for me in ['foo', 'bar']: 
    u[me] = make_callback(me) 

>>> u["foo"]() 
'I am foo' 
関連する問題