Although it's a bit of a cheat, if you create a wrapper of the thing you're iterating, or don't mind closing it (it's probably best to wrap it unless you know what it is), both generators and list comprehensions can be "while iterated" using this approach: 

[item for item in items if condition or items.close()]

When I tested it earlier with a 1000 entries 5 times and had forgotten the parens on close(), it made it really obvious there would be times when the wrapping overhead wasn't a problem: 

On Jan 30, 2013, at 9:02 AM, Shane Green <> wrote:

Nice catch.  New times, 

>>> timeit.timeit(var1)
>>> timeit.timeit(var2)
>>> timeit.timeit(var3)
>>> timeit.timeit(var4)

And I accidentally ran this (without parens), so it was a regular comprehension: 
def var5(count=1000):
    seq = (i for i in xrange(count))
    return [i for i in seq if i < 50 or seq.close]

>>> timeit.timeit(var5)

Then fixed it: 
>>> timeit.timeit(var5)

Shane Green
805-452-9666 |

Begin forwarded message:

Subject: RE: [Python-ideas] while conditional in list comprehension ??
Date: January 30, 2013 8:40:51 AM PST
To: 'Shane Green' <>

Careful! You’re using range() in the slow ones, but xrange() in the fast ones.
With the input seq being much longer than the output, differences in the time it takes to produce the range object may be important.
From: Shane Green [
Sent: Wednesday, January 30, 2013 5:37 PM
To: Wolfgang Maier
Subject: Re: [Python-ideas] while conditional in list comprehension ??
>>> def var1(count=1000):
...     def _gen():
...          for i in range(count):
...               if i > 50: break
...               yield i
...     return list(_gen())
>>> def var2(count=1000):
...     def stop():
...          raise StopIteration
...     return list(i for i in range(count) if i <= 50 or stop())
>>> def var3(count=1000):
...     return [i for i in itertools.takewhile(lambda n: n <= 50, range(count))]
>>> def var4(count=1000):
...     return [i for i in itertools.takewhile(functools.partial(, 50)
>>> def var5(count=1000):
...     seq = (i for i in xrange(count))
...     return [i for i in seq if i < 50 or seq.close()]
>>> timeit.timeit(var1)
>>> timeit.timeit(var2)
>>> timeit.timeit(var5)
Shane Green
805-452-9666 |
On Jan 30, 2013, at 8:17 AM, Wolfgang Maier <> wrote:

list(i for i in a if i < 5000 or a.close())

Shane Green
408-692-4666 |

On Jan 30, 2013, at 10:05 AM, Oscar Benjamin <> wrote:

On 30 January 2013 17:56, Yuriy Taraday <> wrote:

On Wed, Jan 30, 2013 at 1:46 PM, Wolfgang Maier
<> wrote:

your condition is 'partial(lt,50)', but this is not met to begin with and
results in an empty list at least for me. Have you two actually checked
output of the code or have you just timed it?

Yeah. Shame on me. You're right. My belief in partial and operator module
has been shaken.

This is why I prefer this stop() idea to any of the takewhile()
versions: regardless of performance it leads to clearer code, that can
be understood more easily.

Python-ideas mailing list