Or you could try this as an alternative:

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


Op 29/06/2022 om 12:43 schreef Johannes Bauer:
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