I want to construct a value in a list comprehension, but also filter on that value. For example:
[expensive_function(x) for x in generator where expensive_function(x) < 5]
I want to avoid calling expensive_function
twice per iteration.
The generator
may return an infinite series, and list comprehensions aren't lazily evaluated. So this wouldn't work:
[y in [expensive_function(x) for x in generator where expensive_function(x)] where y < 5]
I could write this another way, but it feels right for a list comprehension and I'm sure this is a common usage pattern (possible or not!).
List comprehensions cannot contain statements, only expressions. In fact, that's true for all expressions in Python: they can only contain other expressions. So, no, you can't put a return inside a list comprehension.
List comprehensions are used for creating new lists from other iterables. As list comprehensions return lists, they consist of brackets containing the expression, which is executed for each element along with the for loop to iterate over each element.
One main benefit of using a list comprehension in Python is that it's a single tool that you can use in many different situations. In addition to standard list creation, list comprehensions can also be used for mapping and filtering. You don't have to use a different approach for each scenario.
If generator
may be infinite, you do not want to use a list comprehension. And not everything has to be a one-liner.
def filtered_gen(gen):
for item in gen:
result = expensive_function(item)
if result < 5:
yield result
I'm going to answer the part of the question about how to capture intermediate results in a list comprehension for use in a condition, and ignore the question of a list comprehension built from an infinite generator (which obviously isn't going to work), just in case anyone looking for an answer to the question in the title comes here.
So, you have a list comprehension like this:
[expensive_function(x) for x in xrange(5) if expensive_function(x) % 2 == 0]
And you want to avoid calculating expensive_function
twice when it passes your filter. Languages with more expressive comprehension syntax (Scala, Haskell, etc) allow you to simply assign names to expressions calculated from comprehension variables, which lets you do things like the following:
# NOT REAL PYTHON
[result for x in xrange(5) for result = expensive_function(x) if result % 2 == 0]
But you can easily emulate this by turning the assignment result = expensive_function(x)
into another for
iteration over a sequence of one element:
[result for x in xrange(5) for result in (expensive_function(x),) if result % 2 == 0]
And the proof:
>>> def expensive_function(x):
print 'expensive_function({})'.format(x)
return x + 10
>>> [expensive_function(x) for x in xrange(5) if expensive_function(x) % 2 == 0]
expensive_function(0)
expensive_function(0)
expensive_function(1)
expensive_function(2)
expensive_function(2)
expensive_function(3)
expensive_function(4)
expensive_function(4)
[10, 12, 14]
>>> [result for x in xrange(5) for result in (expensive_function(x),) if result % 2 == 0]
expensive_function(0)
expensive_function(1)
expensive_function(2)
expensive_function(3)
expensive_function(4)
[10, 12, 14]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With