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

-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to