The solution (the best if you have a repeating value of x) is to memoize the function f, that is, create a wrapper function that saves the argument by which the function is called, and saves it than returning it if the same value is given.
A really simple implementation is as follows:
storage = {} def memoized(value): if value not in storage: storage[value] = f(value) return storage[value] [memoized(x) for x in l if memoized(x)]
and then use this function in the list comprehension. This approach is valid under two conditions: one theoretical and one practical. The first is that the function f must be deterministic, i.e. It returns the same results with the same input, and the other - in that the object x can be used as a dictionary of keys. If the first of them is invalid, you must recalculate f each time by definition, and if the second fails, you can use slightly more reliable approaches.
You can find many memoization implementations on the net, and I think there is something in the new versions of python that is included in them.
On a side note, never use small L as a variable name, this is a bad habit, as it can be confused with i or 1 on some terminals.
EDIT:
as commented, a possible solution using generators (to avoid creating useless duplicate times) would be this expression:
[g(x, fx) for x, fx in ((x,f(x)) for x in l) if fx]
You need to weigh your choice, given the computational cost f, the number of duplicates in the original list, and the memory at your location. Remembering makes a compromise between cosmic speeds, which means that it keeps track of every result, keeping it, so if you have huge lists, it can become costly on the front of the memory.