TL;DR your 2nd one is not "that" valid:
>>> old_list = list(range(9))
>>> f = lambda x: x ** 3
>>> [fx := f(x) for x in old_list if fx in {1, 8, 343}]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <listcomp>
NameError: name 'fx' is not defined
>>>
Explanation
In your first list comprehension, [fx for x in old_list if (fx := f(x)) in {1, 8, 343}]
, the fx :=
creates a variable outside of it:
>>> old_list = list(range(9))
>>> f = lambda x: x ** 3
>>> [fx for x in old_list if (fx := f(x)) in {1, 8, 343}]
[1, 8, 343]
>>> fx
512
If you run [fx := f(x) for x in old_list if fx in {1, 8, 343}]
afterwards, it will go like this:
for x in old_list
binds x to 0
if fx in {1, 8, 343}
, fx being the old 512
which is false
- as the if is false, the "select" (left) part is not executed, no call to f, no rebinding of fx, fx is still 512.
- assign x as the 2nd element of old_list, being 1
- ...
We can double check this interpretation like this:
>>> [print("no no no") for x in old_list if fx in {1, 8, 343}]
[]
no no no
is never printed, so this side is never executed (as fx
is 512, not in the set
).