Creating lambdas inside generator expression

Johannes Bauer dfnsonfsduifb at gmx.de
Wed Jun 29 06:43:19 EDT 2022


Aha!

conds = [ lambda msg, z = z: msg.hascode(z) for z in ("foo", "bar") ]

Is what I was looking for to explicitly use the value of z. What a
caveat, didn't see that coming.

Learning something new every day.

Cheers,
Joe


Am 29.06.22 um 11:50 schrieb Johannes Bauer:
> Hi list,
> 
> I've just encounted something that I found extremely unintuitive and
> would like your feedback. This bit me *hard*, causing me to question my
> sanity for a moment. Consider this minimal example code (Py 3.10.4 on
> Linux x64):
> 
> 
> class Msg():
> 	def hascode(self, value):
> 		print("Check for", value)
> 		return False
> 
> conds = [
> 	lambda msg: msg.hascode("foo"),
> 	lambda msg: msg.hascode("bar"),
> ]
> 
> msg = Msg()
> print(conds[0](msg))
> print(conds[1](msg))
> 
> 
> 
> It works perfectly and does exactly what it looks like. The output is:
> 
> Check for foo
> False
> Check for bar
> False
> 
> But now consider what happens when we create the lambdas inside a list
> comprehension (in my original I used a generator expresison, but the
> result is the same). Can you guess what happens when we create conds
> like this?
> 
> conds = [ lambda msg: msg.hascode(z) for z in ("foo", "bar") ]
> 
> I certainly could not. Here's what it outputs:
> 
> Check for bar
> False
> Check for bar
> False
> 
> I.e., the iteration variable "z" somehow gets bound inside the lambda
> not by its value, but by its reference. All checks therefore refence
> only the last variable.
> 
> This totally blew my mind. I can understand why it's happening, but is
> this the behavior we would expect? And how can I create lambdas inside a
> generator expression and tell the expression to use the *value* and not
> pass the "z" variable by reference?
> 
> Cheers,
> Joe



More information about the Python-list mailing list