2010-08-07 6 views
39

Я пытаюсь создать функции внутри цикла и хранить их в словаре. Проблема в том, что все записи в словаре кажутся окончанием сопоставления с последней созданной функцией. Код выглядит следующим образом:Создание функций в цикле

d = {} 
def test(**kwargs): 
    for k in kwargs: 
     def f(): 
      print k, kwargs[k] 
     d[k] = f 
     f() 

test(foo=1, bar=2) 
print 'should print the same output as before' 
d['foo']() 
d['bar']() 

Это выходы:

foo 1 
bar 2 
should print the same output as before 
bar 2 
bar 2 

Любая идея, почему?

+1

в качестве напоминания о себе: http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures –

ответ

82

Вы бежите в проблему с поздним связыванием - каждая функция смотрит k как можно позже (таким образом, при вызове вне test, это происходит после того, как в конце цикла).

Легко фиксируется принуждая раннее связывание: изменение def f(): к def f(k=k): - значения по умолчанию (правую k в k=k значение по умолчанию для имени аргумента k, что левая k в k=k) ищутся в def время, а не на call времени, так что, по сути, это способ специально найти раннее связывание.

Если вы беспокоитесь о f получает дополнительный аргумент (и, следовательно, потенциально называют ошибочно), что есть более сложный способ, который связан с использованием закрытия в качестве «фабрики функций»:

def make_f(kwargs, k): 
    def f(): 
     print k, kwargs[k] 
    return f 

и в ваш цикл использует f = make_f(kwargs, k) вместо инструкции def.

Смежные вопросы