Paul said:
I prefer:
newlist = list(x for x in oldlist if x != 0)
to the square bracket list comprehension that a few people have
suggested. This is because in python 2.x, the listcomp "leaks" its
index variable into the surrounding scope, but the generator
expression above doesn't.
As you indicated, that's been fixed in Py3, though. So if your code works
in Py3.x, you can be somewhat sure that the leak doesn't have side effects.
Plus, it's pretty easy to ignore those leaks as long as you use a suitable
name for the loop variable.
Also note that the performance characteristics may not be identical in both
cases, depending on where you run your code. Cython, for example, will
write a list comprehension out as a rather straight C loop, but when we
implement generator expressions in Cython, it may have to get turned into a
generator function instead of a loop, so that you'd get a much larger
overhead than for the plain list comprehension (although in the simple case
above it would likely get optimised away).
CPython shows a similar difference:
$ python3.1 -m timeit '[x for x in range(1000) if x]'
10000 loops, best of 3: 170 usec per loop
$ python3.1 -m timeit -s 'r=[i%2 for i in range(2000)]' \
'[x for x in r if x]'
1000 loops, best of 3: 222 usec per loop
$ python3.1 -m timeit 'list(x for x in range(1000) if x)'
1000 loops, best of 3: 227 usec per loop
$ python3.1 -m timeit -s 'r=[i%2 for i in range(2000)]' \
'list(x for x in r if x)'
1000 loops, best of 3: 280 usec per loop
Not that I'd consider those numbers worth bothering...
Stefan