Wait, it was much simpler than thatů

>>> def until(items):
...     stops = []
...     def stop():
...             stops.append(1) 
...     yield stop
...     items = iter(items)
...     counter = 0
...     while not stops:
...             yield next(items)
...             print(counter)
...             counter += 1
>>> gen = until(range(15))
>>> stop = next(gen)
>>> [x for x in gen if x < 3 or stop()]
[0, 1, 2]

I must have just been up for too long that this looks like something new to me.

Shane Green 
408-692-4666 | shane@umbrellacode.com

On Jan 29, 2013, at 3:37 PM, Yuriy Taraday <yorik.sar@gmail.com> wrote:

On Tue, Jan 29, 2013 at 7:44 PM, Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de> wrote:
list(i for i in range(100) if i<50 or stop())
Really (!) nice (and 2x as fast as using itertools.takewhile())!

I couldn't believe it so I had to check it:

from __future__ import print_function
import functools, itertools, operator, timeit

def var1():
    def _gen():
        for i in range(100):
            if i > 50: break
            yield i
    return list(_gen())

def var2():
    def stop():
        raise StopIteration
    return list(i for i in range(100) if i <= 50 or stop())

def var3():
    return [i for i in itertools.takewhile(lambda n: n <= 50, range(100))]

def var4():
    return [i for i in itertools.takewhile(functools.partial(operator.lt, 50), range(100))]

if __name__ == '__main__':
    for f in (var1, var2, var3, var4):
        print(f.__name__, end=' ')

Results on my machine:

var1 20.4974410534
var2 23.6218020916
var3 32.1543409824
var4 4.90913701057

var1 might have became the fastest of the first 3 because it's a special and very simple case. Why should explicit loops be slower that generator expressions?
var3 is the slowest. I guess, because it has lambda in it.
But switching to Python and back can not be faster than the last option - sitting in the C code as much as we can.


Kind regards, Yuriy.
Python-ideas mailing list