2017-06-06 243 views
0

爲什麼這不起作用?如何在循環內定義函數

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

我得到的輸出是:

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

看來callback在最新的迭代定義一次。

編輯

提議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閉包在詞法上與後期綁定行爲有關。 –

回答

5

所有的函數都引用相同的變量me。當您嘗試調用該函數時,me的值爲'bar',因爲循環結束時就是這樣。

如果您想要me爲函數的每個定義採用不同的值,那麼每個函數都需要它自己的變量副本。

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

如果你願意,你可以縮短,爲:

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']不應該在所有返回一個字符串,但一個功能句柄。 :)編輯:這句話不再相關。

二,您的功能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'