3

所以这里有一些代码可以简化我一直在做的事情:

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,为什么 cindy 会显示两次?

4

2 回答 2

5

您遇到了经典的绑定时间问题,@Mike 的解决方案是经典的。一个不错的选择是编写一个高阶函数:

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

commands.append(makecall(kwargs))在你的循环中使用。两种解决方案的工作原理相同(通过传递参数强制早期绑定——在我的例子中是一个普通参数,@Mike's 中命名参数的默认值);选择只是风格或优雅的问题(我,虽然我容忍lambda在超级简单的情况下,只要最微妙的复杂性介入,我非常喜欢旧的def;-)。

于 2010-06-24T04:35:59.837 回答
4

在调用函数之前,不会运行函数的主体。当您这样做时lambda: a_function(**kwargs),在您实际调用该函数kwargs之前不会查找。此时,它被分配给您在循环中创建的最后一个。

获得您想要的结果的一种解决方案是commands.append(lambda kwargs=kwargs: a_function(**kwargs))

于 2010-06-24T04:28:36.987 回答