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,为什么 cindy 显示两次?
So here is some code that simplifies what I've been working on:
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()
And here is its output:
{'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
I would expect to get charlie, then cindy, why is cindy being displayed twice?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您遇到了一个经典的绑定时间问题,@Mike 的解决方案就是经典的解决方案。一个好的替代方法是编写一个高阶函数:
并在循环中使用commands.append(makecall(kwargs))。两种解决方案都遵循相同的原理(通过参数的传递强制进行早期绑定——在我的例子中是一个普通参数,@Mike 中的命名参数的默认值);选择只是风格或优雅的问题(我,虽然我在超级简单的情况下容忍 lambda ,但只要有最微妙的复杂性介入,我就非常喜欢老式的 def ) ;-)。
You're encountering a classic binding-time problem, and @Mike's solution is the classic one. A good alternative is to write a higher order function:
and use
commands.append(makecall(kwargs))
in your loop. Both solutions work on the same principle (by forcing early binding through passage of an argument -- a plain argument in my case, a default value for a named argument in @Mike's); the choice is just a matter of style or elegance (me, while I toleratelambda
in super-simple cases, as long as the subtlest complication intervenes I vastly prefer good olddef
;-).函数体在调用函数之前不会运行。当您执行 lambda: a_function(**kwargs) 时,在您实际调用该函数之前,不会查找
kwargs
。此时,它被分配给您在循环中创建的最后一个。获得您想要的结果的一种解决方案是执行commands.append(lambda kwargs=kwargs: a_function(**kwargs))
A function's body isn't ran until the function is called. When you do
lambda: a_function(**kwargs)
,kwargs
isn't looked up until you actually call the function. At that point it's assigned to the last one you made in the loop.One solution that gets the result you want would be to do
commands.append(lambda kwargs=kwargs: a_function(**kwargs))