The problem

I want to generate a new list from already existing data where I on the one hand do difficult computation on the list and on the other hand check conditions on the result.

Without list comprehension

def compute(element):
    ...
def condition(computed) -> bool:
    ...
old_data = ...
new_data = []

for element in old_data:
    computed = compute(element)
    if condition(computed):
        new_data.append(computed)

Kind of works. But we can do better.

With list comprehension - Part 1

Just a basic list comprehension.

def compute(element):
    ...
def condition(computed) -> bool:
    ...
old_data = ...

new_data = [
    compute(element)
    for element in old_data
    if condition(compute(element))
]

Nice one - just one more line required!
The actual improvement is in the runtime: Every .append() call takes quite some time, while list comprehension is done in the compiled part of the Python interpreter and hence quite faster.

My challenge on this is that compute(element) is called twice. What if the function takes much time for computing?

With list comprehension - Part 2

Enter the walrus operator. We can now do the following:

def compute(element):
    ...
def condition(computed) -> bool:
    ...
old_data = ...

new_data = [
    computed
    for element in old_data
    if condition(computed := compute(element))
]

Quite nice, right?
Bad side fact: It kind of gets ugly to read that code… So do not forget to add loads of comments!

Real-world application - The result

Compared to my previous try (copy the old data and drop elements that I do not want), I just increased runtime of the method by a factor of 15.