2010-06-24 2 views
3

Так вот код, который упрощает то, что я работал на:выделки функции в Python в цикле

vars = { 
    'a':'alice', 
    'b':'bob', 
} 
cnames = ['charlie', 'cindy'] 

commands = [] 

for c in cnames: 
    kwargs = dict(vars) 
    kwargs['c'] = c 
    print kwargs 
    commands.append(lambda:a_function(**kwargs)) 

print commands 

def a_function(a=None, b=None, c=None): 
    print a 
    print b 
    print c 

for c in commands: 
    print "run for "+ repr(c) 
    c() 

А вот его вывод:

{'a': 'alice', 'c': 'charlie', 'b': 'bob'} 
{'a': 'alice', 'c': 'cindy', 'b': 'bob'} 
[<function <lambda> at 0x1001e9a28>, <function <lambda> at 0x1001e9e60>] 
run for <function <lambda> at 0x1001e9a28> 
alice 
bob 
cindy 
run for <function <lambda> at 0x1001e9e60> 
alice 
bob 
cindy 

Я хотел бы ожидать, чтобы получить charlie, затем cindy, почему цинна отображается дважды?

ответ

4

Тело функции не запускается до вызова функции. Когда вы делаете lambda: a_function(**kwargs), kwargs не оглядывается, пока вы на самом деле звоните функция. В этот момент он присваивается последнему, который вы сделали в цикле.

Одно из решений, которое получает результат, который вы хотите бы сделать commands.append(lambda kwargs=kwargs: a_function(**kwargs))

+0

круто, это теперь работает вары = { 'а': 'алиса', 'B': 'боб', } CNAMES = [ 'чарли', 'Cindy'] команд = [] для с в CNAMES: kwargs = Dict (вары) kwargs [ 'с'] = с печати kwargs commands.append (лямбда kwargs = kwargs: a_function (** kwargs)) печати команд def a_function (a = None, b = None, c = None):Распечатайте печать б печать с для с в командах: печать «прогон» + предст (с) с() – NorthIsUp

+0

тьфу, не получил код привет освещения по какой-то причине нет. – NorthIsUp

+0

Форматирование комментариев разочаровывает. –

5

Вы столкнулись с классической проблемой связывания времени, и @ решение Майка является классическим. Хорошая альтернатива, чтобы написать функцию высшего порядка:

def makecall(kwargs): 
    def callit(): 
    return a_function(**kwargs) 
    return callit 

и использовать commands.append(makecall(kwargs)) в цикле. Оба решения работают по одному и тому же принципу (заставляя раннее связывание посредством прохождения аргумента - простой аргумент в моем случае, значение по умолчанию для именованного аргумента в @ Mike's); выбор - это только вопрос стиля или элегантности (я, в то время как я терплю lambda в суперпростых случаях, до тех пор, пока вмешивается самое тонкое осложнение, я очень предпочитаю старый добрый def ;-).

+1

Действительно, использование чего-то подобного или использования 'functools.partial', вероятно, является лучшим решением. 'lambda' в стороне, аргумент ключевого слова является своего рода уродливым местом для хранения состояния. –

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