Python: itertools.islice在循环中无效

2 投票
2 回答
5214 浏览
提问于 2025-04-16 11:56

我有这样的代码:

#opened file f
goto_line = num_lines #Total number of lines
while not found:
   line_str = next(itertools.islice(f, goto_line - 1, goto_line))
   goto_line = goto_line/2
   #checks for data, sets found to True if needed

第一次运行时,line_str 是正确的,但之后每次运行都读取了错误的行。

举个例子,goto_line 一开始是 1000。它能正确读取第 1000 行。然后在下一次循环中,goto_line 变成了 500,但它并没有读取第 500 行,而是读取了离 1000 更近的某一行。

我想在一个大文件中读取特定的行,而不想读取多余的内容。有时候它会跳回到之前的某一行,有时候又会跳到后面的行。

我试过使用 linecache,但我通常不会在同一个文件上多次运行这段代码。

2 个回答

0

你不能这样做(也许根据文件的打开方式,有其他方法)。标准的文件迭代器(其实大多数迭代器——Python的迭代器协议只支持向前迭代)只能向前移动。所以在读取了k行之后,再读取k/2行实际上是读取了k+k/2行。

你可以尝试把整个文件读入内存,但如果数据量很大,可能会占用太多内存。你也可以使用file.seek来在文件中滚动,但这还是挺麻烦的。也许你可以使用内存映射文件?不过这只有在每行大小固定的情况下才行。如果需要的话,你可以提前计算出想要检查的行号,并在一次迭代中保存所有这些行(如果我没记错的话,应该不会太多,大约是int(log_2(line_count)) + 1)。这样你就不需要在读取完整个文件后再回滚了。

6

Python中的迭代器只能使用一次。这一点通过例子最容易理解。下面的代码

from itertools import islice
a = range(10)
i = iter(a)
print list(islice(i, 1, 3))
print list(islice(i, 1, 3))
print list(islice(i, 1, 3))
print list(islice(i, 1, 3))

会输出

[1, 2]
[4, 5]
[7, 8]
[]

切片操作总是从上次停止的地方开始。

让你的代码正常工作的最简单方法是使用 f.readlines() 来获取文件中的所有行,然后用普通的Python列表切片 [i:j]。如果你真的想用 islice(),你可以每次都从头开始读取文件,方法是使用 f.seek(0),但这样做会非常低效。

撰写回答