Reputation: 341
I tried the following code in Python 3.5.1:
>>> f = {x: (lambda y: x) for x in range(10)}
>>> f[5](3)
9
It's obvious that this should return 5
. I don't understand where the other value comes from, and I wasn't able to find anything.
It seems like it's something related to reference - it always returns the answer of f[9]
, which is the last function assigned.
What's the error here, and how should this be done so that it works properly?
Upvotes: 30
Views: 8358
Reputation: 2077
Python scoping is lexical. A closure will refer to the name and scope of the variable, not the actual object/value of the variable.
What happens is that each lambda is capturing the variable x
not the value of x
.
At the end of the loop the variable x
is bound to 9, therefore every lambda will refer to this x
whose value is 9.
Why @ChrisP's answer works:
make_func
forces the value ofx
to be evaluated (as it is passed into a function). Thus, the lambda is made with value ofx
currently and we avoid the above scoping issue.
def make_func(x):
return lambda y: x
f = {x: make_func(x) for x in range(10)}
Upvotes: 34
Reputation: 5942
The following should work:
def make_func(x):
return lambda y: x
f = {x: make_func(x) for x in range(10)}
The x
in your code ends up referring to the last x
value, which is 9
, but in mine it refers to the x
in the function scope.
Upvotes: 9