[Tutor] list comprehension efficiency
Steven D'Aprano
steve at pearwood.info
Sun Feb 19 03:55:15 CET 2012
Bill Allen wrote:
> Generally speaking, are list comprehensions more efficient that the
> equivalent for loop with interior conditionals for a given task? Do they
> compile down to the same Python byte code?
It depends, and no.
For-loops are more general, so there are loops that can't be written as list
comprehensions. Consequently, so is the byte code generated. Python makes no
attempt to analyse a for-loop and decide that it could be written as a list
comp. Nor do list comps generate the exact same code as a for-loop: they
can't, because the semantics are slightly different.
(Specifically, a list comp is an atomic operation: either the whole thing
succeeds, or the resultant list does not persist. That same does not apply to
for-loops.)
You can inspect the byte code produced by using the dis module.
But, for the subset of possible for-loops which can be re-written as list
comps, yes, list comps often are more efficient, as building the list can be
performed at full C speed instead of at relatively slower Python speed. But
don't over-estimate how big a difference that makes in practice. For trivial
loops, it makes a big difference:
py> with Timer():
... _ = [None for i in range(10000)]
...
time taken: 0.004692 seconds
py>
py> with Timer():
... _ = []
... for i in range(10000):
... _.append(None)
...
time taken: 0.020877 seconds
but for loops that do actual, significant work, the difference becomes
correspondingly less important:
py> def func(x):
... y = 2*i**3 - 15*i*i + 17*i + 3
... z = x**0.5/(2*y**2 - 1)
... return (3*z)/(1+z)**1.25
...
py> with Timer():
... _ = [func(i) for i in range(10000)]
...
time taken: 0.210438 seconds
py>
py> with Timer():
... _ = []
... for i in range(10000):
... _.append(func(i))
...
time taken: 0.250344 seconds
If you're interested in using my Timer() code, you can find it here:
http://code.activestate.com/recipes/577896-benchmark-code-with-the-with-statement/
Beware though, that you can't exit out of a list comp early. So if you have
code like this:
collection = []
for x in sorted(sequence):
if x > 10:
break
collection.append(x + 5)
versus this:
collection = [x+5 for x in sorted(sequence) if x <= 10]
Consider what happens if sequence = range(1000000). The for-loop does eleven
iterations, the list-comp does a million. Guess which will be faster? :)
--
Steven
More information about the Tutor
mailing list