有没有一行Python代码可以迭代文件的每一行?

4

大多数情况下,当我读取文件时,最终都会变成这样:

with open('file.txt') as f:
    for line in f:
        my_function(line)

这似乎是一个非常普遍的场景,所以我想到了一种更短的方法,但这种方法安全吗?我的意思是文件会被正确关闭吗?或者您在这种方法中看到其他问题吗?

for line in open('file.txt'):
    my_function(line)

编辑:感谢Eric,这似乎是最好的解决方案。希望我不会因此引发讨论,但是当我们想要在多个操作中使用行(而不仅仅是作为my_function的参数)时,您对此方法有何看法:

def line_generator(filename):
    with open(filename) as f:
        for line in f:
            yield line

然后使用:

for line in line_generator('groceries.txt'):
    print line
    grocery_list += [line]

相较于iterate_over_file,这个函数有什么缺点吗?


在理想情况下,是安全的。但是部署的软件很少处于理想环境中,你很快就需要在代码中加入try/catch语句。这就是这个上下文管理器发挥作用并使你的生活变得更加轻松的地方。 - inspectorG4dget
如果在其中一行中出现编码错误,并且您退出而没有关闭和处理文件句柄,那么如果您遇到仍然保持的大量文件句柄,这可能会导致文件系统上的严重问题。 - Dschoni
好的,很明显没有哪段代码是安全的。但在这个上下文中,我更想知道“这是否比使用 with 更不安全”,或者它是否有缺点。或者你的意思是使用 with 可以解决你提到的问题? - user1308345
3个回答

5
如果您经常需要这个,您可以定义如下内容:
def iterate_over_file(filename, func):
    with open(filename) as f:
        for line in f:
            func(line)


def my_function(line):
    print line,

你的Python代码现在可以写成一行:
iterate_over_file('file.txt', my_function)

2

使用上下文管理器是最好的方法,这几乎排除了你的一行代码解决方案。如果你想要天真地创建一个一行代码的解决方案,你会得到:

with open('file.txt') as f:  for line in f:   my_function(line)   # wrong code!!

这是无效的语法。

因此,如果你非常想要一行代码,你可以这样做:

with open('file.txt') as f:  [my_function(line) for line in f]

但这是不好的做法,因为你只为副作用创建了一个列表推导式(你不关心my_function的返回值)。

另一种方法是

with open('file.txt') as f:  collections.deque((my_function(line) for line in f), maxlen=0)

因此,没有创建列表推导式,您需要使用itertools配方(0大小deque:也没有分配内存)来强制消耗迭代器。

结论:

为了达到“Pythonic / one-liner”的目标,我们牺牲了可读性。

有时候最好的方法并不能在一行中实现。


1

基于Eric的方法,你还可以编写一个使用with打开文件并返回文件的函数,使其更加通用。然而,这样做有以下几点不足:

def with_open(filename):
    with open(filename) as f:
        return f  # won't work!

这种方法行不通,因为当函数返回文件f时,with已经关闭了它。相反,你可以把它变成生成器函数,并yield单独的行:

def with_open(filename):
    with open(filename) as f:
        for line in f:
            yield line

或者更短,使用更新版本的Python: ```html

```
def with_open(filename):
    with open(filename) as f:
        yield from f

并像这样使用它:

for line in with_open("test.txt"):
    print line

或者这个:
nums = [int(n) for n in with_open("test.txt")]    

1
有趣的是,我编辑了问题,询问您同时发布的相同方法 :) 我不知道有更新版本,谢谢。 - user1308345

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接