简体   繁体   English

在循环中在python中调整函数

[英]currying functions in python in a loop

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? 我希望得到查理,然后cindy,为什么cindy被展示两次?

You're encountering a classic binding-time problem, and @Mike's solution is the classic one. 您遇到了经典的绑定时间问题,@ Mike的解决方案是经典的解决方案。 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. 并在循环中使用commands.append(makecall(kwargs)) 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); 两个解决方案都遵循相同的原则(通过参数的通过强制早期绑定 - 在我的情况下是一个普通的参数,@ Mike的命名参数的默认值); 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 ;-). 选择只是风格或优雅的问题(我,虽然我在超简单的情况下容忍lambda ,只要最微妙的复杂介入,我非常喜欢好的旧def ;-)。

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. 当你执行lambda: a_function(**kwargs) ,在实际调用函数之前不会查找kwargs 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)) 获得所需结果的一个解决方案是执行commands.append(lambda kwargs=kwargs: a_function(**kwargs))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM