编程新手,希望更深入地了解发生的事情。
目标:打开文件并打印前10行。 (类似于头部命令)
代码:
with open('file') as f:
for i in range(0,10):
print([line.strip('\n') for line in f][i])
结果:打印第一行罚款,然后返回超出范围错误
文件:是一个简单的文本文件,包含20行,每行不超过50个字符
仅供参考 - 删除范围行并打印类型(列表)和长度(20)。打印的特定索引没有问题(除非连续> 1)
能够使用不同的代码获得所需的结果,但尝试使用/ as
进行改进答案 0 :(得分:4)
您实际上可以迭代文件。你应该在这做什么。
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]
元素或文件中的第一行。但是你的文件迭代器位于文件的末尾。
现在我们回到列表的开头i = 1
。现在我们迭代到文件的末尾,但我们已经在最后,所以没有要读取的行,我们有一个空列表[]
,我们试图获取[0]
的元素。但那里什么都没有。所以我们得到IndexError
。
列表推导可以有用,但是当你开始时,编写for循环通常会更容易,然后将其转换为列表理解。所以你可能会这样写:
with open('file') as f:
for i, line in enumerate(file, start=10):
if i < 10:
print(line.rstrip())
现在,我们不应该在列表理解中打印,所以我们将收集所有内容。我们从我们想要的东西开始:
[line.rstrip()
现在添加位:
[line.rstrip() for i, line in enumerate(f)
最后添加过滤器和我们的右括号:
[line.rstrip() for i, line in enumerate(f) if i < 10]
有关列表推导的更多信息,这是一个很棒的资源:http://treyhunner.com/2015/12/python-list-comprehensions-now-in-color/