1

I am trying to create a list of functions(function objects) that print out corresponding items from another list:

strings = ["a", "b", "c"]
functions = []
for i in strings:
    functions.append(lambda: print(i))

What the above code does is create lambda functions which when called print the value of i. I want the items of the strings list and the functions list to have a one-to-one relationship, meaning I want the following results.

Output 1:

    >>> functions[0]()
    'a'
    >>> functions[1]()
    'b'
    >>> functions[2]()
    'c'

But I'm getting this:

Output 2:

    >>> functions[0]()
    'c'
    >>> functions[1]()
    'c'
    >>> functions[2]()
    'c'

I know the variable i in the for loop persists after the end of the loop, and all the functions end up printing out the same value of i.

Is there any way to make the functions print out the corresponding values of the strings list, like Output1 above?

Job
  • 54
  • 6
  • 2
    Does this answer your question? [Creating lambda inside a loop](https://stackoverflow.com/questions/7546285/creating-lambda-inside-a-loop) – buran Oct 09 '21 at 07:31

2 Answers2

6

The lambda lambda: print(i) is not generated with the value of i at the time but rather points to i to print whatever the value is at the time it was called.

>>> f = lambda: print(i)
>>> i = 1
>>> f()
1
>>> i = 2
>>> f()
2

To get around this you can create the function with a default value that is set to a value.

>>> f = lambda i=1: print(i)
>>> f()
1

So your code could become

strings = ["a", "b", "c"]
functions = []
for i in strings:
    functions.append(lambda value=i: print(value))

Alternatively which I would suggest over generating functions is to just pass in the value you want as a parameter.

def func(i):
    print(i)

>>> strings = ["a", "b", "c"]
>>> func(strings[0])
'a'

If you don't like that the lambda function is using a default value, then you can use functools.partial to create your functions

from functools import partial

def func(i):
    print(i)

strings = ["a", "b", "c"]
functions = []
for i in strings:
    functions.append(partial(func, i))
Steven Summers
  • 5,079
  • 2
  • 20
  • 31
2

By doing as you did, your variable i is global and shared among all functions. Thus when you increment i in the loop, it increments for all functions.

You need to make your variable local to each function.

One way is to pass an argument:

strings = ["a", "b", "c"]
functions = []
for i in strings:
    def myfunc(i=i):
        print(i)
    functions.append(myfunc)
    
functions[0]()

output: a

mozway
  • 194,879
  • 13
  • 39
  • 75