In the Effective Python book, the author recommends using assignment expressions to avoid redundancy in comprehensions, for example:
def fun(i):
return 2 * i
result = {x: y for x in [0, 1, 2, 3] if (y := fun(x)) > 3}
instead of
result = {x: fun(x) for x in [0, 1, 2, 3] if fun(x) > 3}
result
has the value {2: 4, 3: 6}
.
The author states that
If a comprehension uses the walrus operator in the value part of the comprehension and doesn’t have a condition, it’ll leak the loop variable into the containing scope. [...] It’s better not to leak loop variables, so I recommend using assignment expressions only in the condition part of a comprehension.
However, in the example above, y
is set to 6 at the end of the program. So, the variable in the assignment expression leaked, although it is defined in the condition.
The same thing happens for list comprehensions:
>>> _ = [(x, leak) for x in range(4) if (leak := 2 * x) > 3]
>>> leak
6
And even for generator expressions:
>>> it = ((x, leak) for x in range(4) if (leak := 2 * x) > 3)
>>> next(it)
(2, 4)
>>> leak
4
>>> next(it)
(3, 6)
>>> leak
6
What am I missing? Is there any way to avoid leaking in assignment expressions in comprehensions at all?