如何在Python中逐行读取文件?

2024-04-19 16:38:10 发布

您现在位置:Python中文网/ 问答频道 /正文

在史前时代(Python1.4),我们做到了:

fp = open('filename.txt')
while 1:
    line = fp.readline()
    if not line:
        break
    print line

在Python2.1之后,我们做到了:

for line in open('filename.txt').xreadlines():
    print line

在我们得到Python2.3中方便的迭代器协议之前,可以:

for line in open('filename.txt'):
    print line

我见过一些使用更详细的示例:

with open('filename.txt') as fp:
    for line in fp:
        print line

这是未来的首选方法吗?

[编辑]我得到with语句确保关闭文件。。。但是为什么文件对象的迭代器协议中没有包含这个呢?


Tags: 文件intxt协议forreadlineifwith
3条回答

如果被额外的一行关闭,可以使用这样的包装函数:

def with_iter(iterable):
    with iterable as iter:
        for item in iter:
            yield item

for line in with_iter(open('...')):
    ...

在Python 3.3中,yield from语句将使此过程更短:

def with_iter(iterable):
    with iterable as iter:
        yield from iter

有一个原因可以说明为什么我们更喜欢以下内容:

with open('filename.txt') as fp:
    for line in fp:
        print line

我们都被CPython相对确定的垃圾收集引用计数方案破坏了。另外,如果Python的假想实现使用其他方案来回收内存,那么如果没有with块,它们不一定“足够快”地关闭文件。

在这种实现中,如果代码打开文件的速度快于垃圾收集器对孤立文件句柄调用终结器的速度,则可能会从操作系统中收到“打开的文件太多”错误。通常的解决方法是立即触发GC,但这是一种令人讨厌的攻击,必须通过每个可能遇到错误的函数(包括库中的函数)来完成。真是个噩梦。

或者您可以使用with块。

奖金问题

(如果只对问题的客观方面感兴趣,现在就停止阅读。)

Why isn't that included in the iterator protocol for file objects?

这是一个关于API设计的主观问题,所以我有两个主观的答案。

在直觉层面上,这感觉是错误的,因为它使迭代器协议在行和行上执行两个独立的迭代操作关闭文件句柄,而让一个看起来简单的函数执行两个操作通常是一个坏主意。在这种情况下,感觉特别糟糕,因为迭代器以准函数的、基于值的方式与文件内容相关,但管理文件句柄是一项完全独立的任务。将两者无形地压缩到一个动作中,对于阅读代码的人来说是令人惊讶的,这使得对程序行为进行推理变得更加困难。

其他语言基本上也得出了同样的结论。Haskell简要地提到了所谓的“lazy IO”,它允许你遍历一个文件,并在到达流的末尾时自动关闭它,但是现在几乎普遍不鼓励在Haskell中使用lazy IO,Haskell用户大多已经转向更显式的资源管理,比如行为更像Python中的with块。

在技术层面上,您可能需要对Python中的文件句柄执行一些操作,如果迭代关闭了文件句柄,这些操作将无法正常工作。例如,假设我需要在文件上迭代两次:

with open('filename.txt') as fp:
    for line in fp:
        ...
    fp.seek(0)
    for line in fp:
        ...

虽然这是一个不太常见的用例,但请考虑这样一个事实:我可能刚刚将底部的三行代码添加到了原来位于前三行的现有代码基中。如果迭代关闭了文件,我就不能这么做。因此,将迭代和资源管理分开,可以更容易地将代码块组合成一个更大的、可工作的Python程序。

可组合性是语言或API最重要的可用性特性之一。

是的

with open('filename.txt') as fp:
    for line in fp:
        print line

是一条路。

不是很冗长。它更安全。

相关问题 更多 >