1

I saved lambda functions in an array, but when i tried to call for example the first or second function, always the last one added to the array is called. But when I call them in a for-loop they are called correctly. How can I call the functions correctly using the position? And why does this happen?

The following code is how I tried to isolate the problem. pos=2 always returns ten times 9 (always calls the last appended function) and pos=1 returns always 0 to 9 (how I would want it to be).

l=[i for i in range(10)]

#the list of the functions
funcs=[]

#the used call-possibility 
pos= #1/2

#initialising of the functions
for i in l:
    funcs.append(lambda:print(i))



#possibilities of calling the functions
if pos==1:
    for i in range(len(l)):
        print(l[i])
        funcs[i]()

if pos==2:
    x=0
    while x<10:
        funcs[x]()
        x+=1
quamrana
  • 37,849
  • 12
  • 53
  • 71
  • All of the lambdas in `funcs` are printing the *current* value of `i`, not the value it had when the lambdas were created. So they are all equivalent. After creating them, if you do `i = 0` then they will all print `0`. If you do `i = 5` then they will all print `5`. To avoid that, you need to decouple the lambdas from the global copy of `i`. – Tom Karzes Aug 08 '21 at 17:28
  • You can fix it by defining a function such as `def make_lambda(i): return lambda: print(i)` Then in your loop you can do `funcs.append(make_lambda(i))`. This will effectively give each lambda its own, frozen copy of `i`. – Tom Karzes Aug 08 '21 at 17:31
  • I tried using copies before didnt work either – mybrainisrunningoutofmyears Aug 08 '21 at 17:31
  • @TomKarzes thanks! do you mind explaining to me why it always uses the current value of "i" ? – mybrainisrunningoutofmyears Aug 08 '21 at 17:35
  • @TomKarzes i didnt see your second comment when i wrote the first comment sry, i tried using the copy library and was hoping it would have the effect of "freezing" the "i" – mybrainisrunningoutofmyears Aug 08 '21 at 17:36
  • Because the lambdas don't make their own copies of the variables they reference, *except* for the arguments to the lambda. – Tom Karzes Aug 08 '21 at 17:36
  • @TomKarzes ok thx want to add your first two comments as an answer so i can give you credit for it ? – mybrainisrunningoutofmyears Aug 08 '21 at 17:38
  • Another way to solve this problem would be to do `funcs.append(lambda i=i: print(i))`. This works by giving the lambda an argument, but making it optional with a default value of the value of `i` at the time the lambda is created. It's not quite the same, since you could then override the optional argument when calling the function, but as long as you avoid that you won't notice the difference. – Tom Karzes Aug 08 '21 at 17:38
  • Thanks for the offer, but this question has already been closed as a duplicate, so no answers can be posted. – Tom Karzes Aug 08 '21 at 17:39
  • @TomKarzes oh ok but again thank you for taking your time and explaining it to me quickly, now i can finally go to sleep :D – mybrainisrunningoutofmyears Aug 08 '21 at 17:41
  • No problem, glad I could help! This is related to the notion of closures, which can be confusing if you aren't used to them. – Tom Karzes Aug 08 '21 at 17:42

0 Answers0