Question: Question:
The following two codes behave differently in Python3:
fs = [lambda x: i*x for i in range(3)]
for i in range(3):
print(fs[i](3))
This is output as 6 6 6
fs2 = []
for i in range(3):
fs2.append(lambda x: i*x)
for i in range(3):
print(fs2[i](3))
This is output as 0 3 6
.
At first glance, they seem to behave the same, but why do they behave differently?
Answer: Answer:
In Python, variables are bound when a lambda or function references an external value.
Roughly explaining what's happening this time, fs = [lambda x: i*x for i in range(3)]
is a variable (0,1,2) instead of binding the real value (0,1,2) for each loop. i) It is binding itself. Therefore, the value of the bound variable i
changes for each loop, and the final value (i = 2) ends in the bound state.
As a result, when used later, the bound variable i
of i*x
is always 2, so 2*x
=> 2*3=6
.
8/24 postscript
With this explanation, I can understand the output of the first 6 6 6 but not the behavior of the latter. – Termoshtt
I've received your comments, so I'll explain the latter code as well.
I explained earlier that "not binding the real value (0,1,2), but binding the variable (i) itself", but this behavior also occurs in the latter code.
The first for loop uses the variable i, and the second for loop also uses the variable i. Therefore, the variable i
bound to lambda is not the final value of i in the first for loop (i = 2), but the value of i used in the second for loop (0,1). Refer to, 2).
Therefore, fs2[i](3)
is (lambda x: x*i)(3)
, but i changes to 0,1,2. As a result, the values 0 * 3 = 0, 1 * 3 = 3, 2 * 3 = 6 are printed.
So what if the variable name of the second for loop is j
instead of i
?
>>> fs2 = []
>>> for i in range(3):
... fs2.append(lambda x: i*x)
...
>>> for i in range(3):
... print(fs2[i](3))
...
0
3
6
>>> for j in range(3):
... print(fs2[j](3))
...
6
6
6
Since it was fixed at i = 2, the printed value was always 2*3=6
.
The following pages will be helpful for detailed explanations.