Python currying functions in a loop

So here is some code that simplifies what I was 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 his conclusion:

{'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 and then cindy, why is cinnamon displayed twice?

+3
source share
2 answers

The function body does not start until the function is called. When you execute lambda: a_function(**kwargs), it is kwargsnot browsed until you actually call the function. At this point, it is assigned to the last one you made in the loop.

One solution that gets the desired result would be to make commands.append(lambda kwargs=kwargs: a_function(**kwargs))

+4
source

, @Mike . :

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

commands.append(makecall(kwargs)) . ( - , @Mike's); - (, lambda , , def; -).

+5

Source: https://habr.com/ru/post/1751503/


All Articles