3

Consider this short code snippet:

class X:
    pass

xs = []
for s in ("one", "two", "three"):
    x = X()
    x.f = lambda: print(s)
    xs.append(x)

for x in xs:
    x.f()

It outputs:

three
three
three

I thought the result should be like this instead:

one
two
three

Why is that not the actual result?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
grześ
  • 467
  • 3
  • 21

2 Answers2

2

Your lambda function holds reference to s, hence the last assigned value to s is printed when called outside that for loop. Try the below code for your expected behaviour. Here a copy of that existing reference s is created in v as function argument and that value is printed inside the function f.

class X:
    pass

xs = []
for s in ("one", "two", "three"):
    x = X()
    def f(v=s): print(v)
    x.f = f
    xs.append(x)

for x in xs:
    x.f()

Output:

one
two
three
Praveenkumar
  • 2,056
  • 1
  • 9
  • 18
2

It happens because the s variable is a reference, not a value. And the value by reference will be resolved when it will be called, not created. To resolve the value in the creation time use the default argument.

lambda s=s: print(s)
MartenCatcher
  • 2,713
  • 8
  • 26
  • 39