【问题标题】:File open: Is this bad Python style?文件打开:这是不好的 Python 风格吗?
【发布时间】:2010-11-25 07:27:54
【问题描述】:

读取文件内容:

data = open(filename, "r").read()

打开的文件立即停止在任何地方被引用,因此文件对象最终将关闭......并且它不应该影响使用它的其他程序,因为该文件只打开用于读取,而不是写入。

编辑:这实际上在我写的一个项目中咬了我——它促使我问this 问题。只有在内存不足时才会清理文件对象,而不是在文件句柄用完时。因此,如果您过于频繁地执行此操作,最终可能会耗尽文件描述符并导致 IO 尝试打开文件时引发异常。

【问题讨论】:

  • 请注意,这会将整个文件读入内存,无论它有多大。因此,请确保它是您可以处理的文件。除此之外,我同意答案。
  • @balpha:但答案是相互矛盾的。 ;)(我想你是在所有答案都出来之前发表评论的。)

标签: python file file-io coding-style


【解决方案1】:

仅作记录: 这只是稍长一些,并立即关闭文件:

from __future__ import with_statement

with open(filename, "r") as f:
    data = f.read()

【讨论】:

  • +1 我添加了 import 以防万一他们使用 Python 2.5 :)
  • 一个后续风格问题:with open("t1.py", "r") as f: f.read() all on one 真的很糟糕吗?线?我知道它不那么可读,但通常,读入文件是一种非常基本的事情,下一个阅读代码的人真的不在乎你是怎么做到的。
  • @Jenn D:with 的一点是将所有处理限制在一个整洁的范围内。将with open() as f: f.read() 放在一行中会破坏with 的作用域目的。
  • 这根本没有意义。范围是相同的,无论是否有换行符。我不喜欢它作为风格,但范围没有进入它。
  • @Glenn:这不是换行符,而是整个缩进套件。 with 的目的是在一个紧密绑定的上下文中读取和处理数据。使用单行 with this as that: variable= that.read() 是您现在有了 with 块的副作用,失去了整洁的绑定。
【解决方案2】:

确实它最终会关闭,但最终可能还不够快。特别是如果你在循环中使用它,系统可能会在 GC 到达文件对象之前用完文件句柄。

【讨论】:

  • 但是如果fileobj被引用计数了..它直接变成0并立即删除?在 CPython(?) 中。
  • @kaizer.se:它仍然不一定会立即删除。仅当 CPython 需要更多内存时。
  • 等等我错了。它应该被立即删除,因为这就是引用计数的工作方式。除非文件对象本身有一些循环。这个答案是错误的吗?如果不是,那么为什么不立即删除对象?
【解决方案3】:

代码完全按照你说的那样工作,但它的风格很糟糕。您的代码依赖于现在可能正确但并不总是正确的假设。您的代码将在文件被打开而不是关闭的情况下运行确实,这并非不可能。仅保存 1 或 2 行代码真的值得冒险吗?我不这么认为。

【讨论】:

    【解决方案4】:

    不,根据您的推理,这是完全合理的 Python 风格 IMO。

    更新:这里有很多关于文件对象是否被立即整理的问题。我没有推测,而是进行了一些挖掘。这是我看到的:


    来自 Python 的 object.h 中的评论:

    宏 Py_INCREF(op) 和 Py_DECREF(op) 用于递增或 减少引用计数。 Py_DECREF 调用对象的释放器 当引用计数下降到 0 时函数

    查看 Python 的fileobject.c

    文件对象的函数表指向函数file_dealloc。这个功能 调用close_the_file,然后关闭文件。


    所以说目前在 CPython 上,当没有 对文件对象的更多引用,它会立即关闭。如果您认为这种解释是错误的,请发表评论说明您为什么会有这种感觉。

    【讨论】:

    • 还算合理,但操作系统资源可能不像您希望的那样完全可用。例如,尝试在读取文件后立即删除它可能不起作用,因为操作系统资源由底层 C 库持有,即使 Python file 对象已被垃圾收集。在操作系统认为该文件不再使用之前,您可能无法将其删除。
    • @S. Lott:你是说垃圾收集的file 对象没有关闭(以便操作系统知道它不再使用)?我会期望删除文件对象会关闭文件,但我在文档中找不到任何内容。
    • 我的理解是,CPython(大多数人在想到 Python 时会想到的参考实现)实际上会在所有未引用的对象离开作用域时销毁它们。在这种情况下,一旦 read() 操作完成,文件对象就会离开范围。所以它应该做你想要的。但是,这不是保证的行为。 Python 的其他实现(我认为 Jython 是一个很好的例子)可能会以不同的方式处理垃圾收集。如果您知道自己使用的是 CPython 并且不关心可移植性,我的直觉是使用简单的实现。
    • 问题不在于垃圾收集本身。这是释放对象与任何操作系统资源之间的关系。我怀疑(但不知道)该对象只是被释放了,并且底层的 OS 文件句柄处于悬空状态。
    • @Jason,这是错误的。我的理解是垃圾收集永远不会发生。
    【解决方案5】:

    即使它按预期工作,我认为它在两个方面失败了:

    1. 您的代码不会无缝扩展,因为您将整个文件读入内存,这可能是也可能不是您想要的。
    2. 根据 Python 的禅宗(在 Python 提示符中尝试import this 来检索它)“显式优于隐式”,并且如果未能显式关闭文件,您可能会混淆某些人留下您的代码进行维护。

    这真的很有帮助! Python 鼓励显式风格。

    除此之外,对于一次性脚本,您的风格很有意义。

    也许你会受益于this answer

    【讨论】:

      【解决方案6】:

      对我来说看起来不错。我经常阅读这样的文件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-13
        • 2010-12-16
        • 2015-12-20
        • 2010-11-02
        • 2020-10-12
        • 2020-10-19
        相关资源
        最近更新 更多