为什么takewhile()跳过第一行?

时间:2011-09-02 01:13:31

标签: python io generator

我有一个这样的文件:

1
2
3
TAB
1
2
3
TAB

我想将TAB之间的行读作块。

import itertools

def block_generator(file):
    with open(file) as lines:
        for line in lines:
            block = list(itertools.takewhile(lambda x: x.rstrip('\n') != '\t',
                                             lines))
            yield block

我想这样使用它:

blocks = block_generator(myfile)
for block in blocks:
    do_something(block)

我得到的所有块都以[2,3] [2,3]之类的第二行开头,为什么?

4 个答案:

答案 0 :(得分:4)

这是另一种使用groupby的方法

from itertools import groupby
def block_generator(filename):
    with open(filename) as lines:
        for pred,block in groupby(lines, "\t\n".__ne__):
            if pred:
                yield block

答案 1 :(得分:2)

在这里,测试代码。使用while True:循环,让itertools.takewhile()使用lines执行所有操作。当itertools.takewhile()到达输入的末尾时,它返回一个迭代器,除了引发StopIteration之外什么都不做,list()只是变成一个空列表,所以一个简单的if not block:测试检测到空列表并突破循环。

import itertools

def not_tabline(line):
    return '\t' != line.rstrip('\n')

def block_generator(file):
    with open(file) as lines:
        while True:
            block = list(itertools.takewhile(not_tabline, lines))
            if not block:
                break
            yield block

for block in block_generator("test.txt"):
    print "BLOCK:"
    print block

如下面的评论中所述,这有一个缺陷:如果输入文本在一行中仅包含制表符两行,则此循环将停止处理而不读取所有输入文本。而且我想不出有任何办法可以干净利落地处理这件事。很遗憾,你从itertools.takewhile()返回的迭代器使用StopIteration 两个作为组末尾的标记,以及你在文件结尾处获得的标记。更糟糕的是,我找不到任何方法来询问文件迭代器对象是否已到达文件结尾。更糟糕的是,itertools.takewhile()似乎立即将文件迭代器推进到文件结尾;当我尝试使用lines.tell()重写上述内容以检查我们的进度时,它已经在第一组之后的文件末尾。

我建议使用itertools.groupby()解决方案。它更干净。

答案 2 :(得分:1)

我认为问题在于你在lambda函数中使用lines而不是line。你的预期产量是多少?

答案 3 :(得分:1)

itertools.takewhile隐式迭代文件的lines以获取块,但for line in lines:也是如此。每次循环时,line都会被抓取,丢弃(因为没有使用line的代码),然后还有一些block在一起。