您实际上可以迭代文件。你应该在这里做什么。
with open('file') as f:
for i, line in enumerate(file, start=1):
# Get out of the loop if we hit 10 lines
if i >= 10:
break
# Line already has a '\n' at the end
print(line, end='')
您的代码失败的原因是您的列表理解:
[line.strip('\n') for line in f]
第一次通过循环消耗文件中的所有行。现在你的文件没有更多的行了,所以下一次通过它创建文件中所有行的列表并尝试获取[1]st 元素。但这不存在,因为文件末尾没有行。
如果您希望大部分代码保持原样,您可以这样做
lines = [line.rstrip('\n') for line in f]
for i in range(10):
print(lines[i])
但这也很愚蠢,因为你可以这样做
lines = f.readlines()
但是如果你只想到第 10 行,那也是 愚蠢的,因为你可以这样做:
with open('file') as f:
print('\n'.join(f.readlines()[:10]))
一些进一步的解释:
修复代码的最短和最差方法是添加一行代码:
with open('file') as f:
for i in range(0,10):
f.seek(0) # Add this line
print([line.strip('\n') for line in f][i])
现在您的代码可以运行了 - 但这是让您的代码运行的一种可怕方式。 原因 你的代码没有按照你期望的方式工作,首先是文件是可消耗的迭代器。这意味着当你从他们那里阅读时,你最终会用完要阅读的东西。这是一个简单的例子:
import io
file = io.StringIO('''
This is is a file
It has some lines
okay, only three.
'''.strip())
for line in file:
print(file.tell(), repr(line))
这个输出
18 'This is is a file\n'
36 'It has some lines\n'
53 'okay, only three.'
现在如果你尝试从文件中读取:
print(file.read())
你会看到它没有输出任何东西。那是因为您已经“使用”了该文件。我的意思是显然它仍在磁盘上,但迭代器已到达文件末尾。但如图所示,可以在文件中查找。
print(file.tell())
file.seek(0)
print(file.tell())
print(file.read())
您会看到打印的整个文件。但是那些其他职位呢?
file.seek(36)
print(file.read()) # => okay, only three.
作为旁注,您还可以指定阅读量:
file.seek(36)
print(file.read(4)) # => okay
print(file.tell()) # => 40
因此,当我们从文件中读取或对其进行迭代时,我们会使用迭代器并到达文件末尾。让我们使用您的新工具并返回到您的原始代码并探索正在发生的事情。
with open('file') as f:
print(f.tell())
lines = [line.rstrip('\n') for line in f]
print(f.tell())
print(len([line for line in f]))
print(lines)
您会看到您位于文件中的不同位置。第二个列表推导产生一个空列表。这是因为在评估列表推导时,它会立即执行。所以当你这样做时:
for i in range(10):
print([line.strip('\n') for line in f][i])
您第一次执行的操作是i = 0,然后列表解析读取到文件末尾。现在它采用列表的[0]th 元素,或文件中的第一行。但是您的文件迭代器位于文件末尾。
所以现在我们回到列表的开头和i = 1。现在我们迭代到文件的末尾,但我们已经到了末尾,所以没有要读取的行,并且我们有一个空列表[],我们尝试获取其中的[0]th 元素。但是那里什么都没有。所以我们得到了一个IndexError。
列表推导可能很有用,但是当您开始时,编写 for 循环然后将其转换为列表推导通常要容易得多。所以你可能会这样写:
with open('file') as f:
for i, line in enumerate(file, start=10):
if i < 10:
print(line.rstrip())
现在,我们不应该在列表推导式中打印,而是收集所有内容。我们首先放置我们想要的:
[line.rstrip()
现在添加 for 位:
[line.rstrip() for i, line in enumerate(f)
最后添加过滤器和我们的右大括号:
[line.rstrip() for i, line in enumerate(f) if i < 10]
有关列表推导的更多信息,这是一个很棒的资源:@987654321@