python 循环中的柯里化函数

发布于 2024-09-06 19:17:57 字数 836 浏览 3 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

×纯※雪 2024-09-13 19:17:57

您遇到了一个经典的绑定时间问题,@Mike 的解决方案就是经典的解决方案。一个好的替代方法是编写一个高阶函数:

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

并在循环中使用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:

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

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 tolerate lambda in super-simple cases, as long as the subtlest complication intervenes I vastly prefer good old def;-).

掐死时间 2024-09-13 19:17:57

函数体在调用函数之前不会运行。当您执行 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))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文