Fate of itertools.dropwhile() and itertools.takewhile()

Paul Hankin paul.hankin at gmail.com
Sun Dec 30 21:50:11 EST 2007


On Dec 31, 1:25 am, Raymond Hettinger <pyt... at rcn.com> wrote:
> FWIW, here is an generator version written without the state flag:
>
>     def iter_block(lines, start_marker, end_marker):
>         lines = iter(lines)
>         for line in lines:
>             if line.startswith(start_marker):
>                 yield line
>                 break
>         for line in lines:
>             if line.startswith(end_marker):
>                 return
>             yield line

Here's a (stateful) version that generates all blocks...

import itertools

def iter_blocks(lines, start_marker, end_marker):
    inblock = [False]
    def line_in_block(line):
        inblock[0] = inblock[0] and not line.startswith(end_marker)
        inblock[0] = inblock[0] or line.startswith(start_marker)
        return inblock[0]
    return (block for is_in_block, block in
        itertools.groupby(lines, line_in_block) if is_in_block)

If you just want the first block (as the original code did), you can
just take it...

for line in iter_blocks(lines, start_marker, end_marker).next():
    ... process lines of first block.

I'm not happy about the way the inblock state has to be a 1-element
list to avoid the non-local problem. Is there a nicer way to code it?
Otherwise, I quite like this code (if I do say so myself) as it neatly
separates out the logic of whether you're inside a block or not from
the code that yields blocks and lines. I'd say it was quite readable
if you're familiar with groupby.

And back on topic... I use itertools regularly (and have a functional
background), but have never needed takewhile or dropwhile. I'd be
happy to see them deprecated.

--
Paul Hankin




More information about the Python-list mailing list