Using break in a list comprehension

I know this is a VERY OLD post, however since OP asked about using break inside a list-comprehension and I was also looking for something similar, I thought I would post my findings here for future reference.

While investigating break, I came across little known feature of iter as iter(callable, sentinel) which return an iterator that "breaks" iteration once callable function value is equal to sentinel value.

>>> help(iter)
Help on built-in function iter in module __builtin__:

iter(...)
    iter(collection) -> iterator
    iter(callable, sentinel) -> iterator

    Get an iterator from an object.  In the first form, the argument must
    supply its own iterator, or be a sequence.
    In the second form, the callable is called until it returns the sentinel.

Tricky part here is defining a function that would fit given problem. In this case first we need to convert given list of numbers to an iterator using x = iter(numbers) which feeds as external variable into lambda function.

Next, our callable function is just a call to the iterator to spit out next value. The iterator then compares with our sentinel value (412 in this case) and "breaks" once that value is reached.

print [i for i in iter(lambda x=iter(numbers): next(x),412) if i %2 == 0]

>>> 
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418,  
 344, 236, 566, 978, 328, 162, 758, 918]

Use a function to raise StopIteration and list to catch it:

>>> def end_of_loop():
...     raise StopIteration
... 
>>> even = list(end_of_loop() if n == 412 else n for n in numbers if 0 == n % 2)
>>> print(even)
[402, 984, 360, 408, 980, 544, 390, 984, 592, 236, 942, 386, 462, 418, 344, 236, 566, 978, 328, 162, 758, 918]

For those complaining it is not a one-liner:

even = list(next(iter(())) if n == 412 else n for n in numbers if 0 == n % 2)

For those complaining it is hackish and should not be used in production code: Well, you're right. Definitely.


You can use generator expressions together with itertools.takewhile():

even_numbers = (n for n in numbers if not n % 2)
list(itertools.takewhile(lambda x: x != 412, even_numbers))

Edit: I just noticed the requirement not to use any imports. Well, I leave this answer here anyway.