在Python中逐行读取首选文件的习惯用法

dbn*_*dbn 6 python file-io idioms

我觉得几乎每次我用Python读取文件时,我想要的就是:

with open("filename") as file_handle:
    for line in file_handle:
        #do something
Run Code Online (Sandbox Code Playgroud)

这真的是首选的成语吗?双重缩进所有文件读取逻辑使我有些恼火。有没有办法将此逻辑分解为一行或一层?

aba*_*ert 3

对于简单的情况,是的,两级withfor是惯用的。

\n\n

对于缩进成为问题的情况,就像 Python 中的其他地方一样,惯用的解决方案是找到一些东西来分解到函数中。

\n\n
\n\n

您可以编写包装器来帮助实现这一点。例如,这里有一个简单的方法来解决您使用的一些问题with(例如,即使在最好的情况下,文件在完成循环后仍然保留,直到作用域结束\xe2\x80\x94,这可以几天后,或者永远不会,如果范围是主事件循环或生成器或其他东西\xe2\x80\xa6):

\n\n
def with_iter(iterable):\n    with iterable:\n        yield from iterable\n\nfor line in with_iter(open("filename")):\n    # do something\n\nfor line in with_iter(open("other_filename")):\n    # do something else\n
Run Code Online (Sandbox Code Playgroud)\n\n

当然它并不能解决所有问题。(有关更多详细信息,请参阅此 ActiveState 配方。)

\n\n

如果您知道它可以满足您的要求,那就太好了。如果您不明白这些差异\xe2\x80\xa6,请遵循惯用语;这是惯用语是有原因的。

\n\n
\n\n

那么,如何重构代码呢?最简单的方法通常是将循环体转换为函数,因此您可以只使用map或 推导式:

\n\n
def do_with_line(line):\n    return line\n\nwith open("filename") as f:\n    process = [do_with_line(line) for line in f]\n
Run Code Online (Sandbox Code Playgroud)\n\n

但如果问题是上面或下面的代码for太深,您将不得不在不同的级别进行重构。

\n

  • 除了这个包装器与直接使用 open() 具有相同的问题之外。资源管理变得不确定,只是现在它取决于正在最终确定的生成器而不是正在最终确定的文件(值得注意的是,循环体中的异常不会*触发文件的“__exit__”)。 (2认同)