【问题标题】:Files gets closed after evaluation of a generator expression [duplicate]评估生成器表达式后文件被关闭[重复]
【发布时间】:2012-08-22 17:29:12
【问题描述】:

假设我有一个文件test.txt 并且想要打印内容。我可以在 Python 中这样做(这只是说明我的问题的示例,而不是好的代码示例):

for i in (line for line in open('test.txt')):
    print ">", i,

我使用strace 确保在代码执行后打开和关闭文件。

问题:为什么文件被关闭了?我想这与上下文管理器有关,但我找不到对这种结构的任何引用以及文件自动关闭的原因。谁知道幕后究竟发生了什么并能解释一下?

【问题讨论】:

    标签: python generator


    【解决方案1】:

    当对文件的引用超出范围时,它会被垃圾回收,并在被删除时关闭。由于您没有为文件分配名称,因此循环结束后,它就会超出范围。然而,这并不是一件值得依赖的好事情。改用实际的上下文管理器,例如:

    with open('test.txt') as f:
        for i in f:
            print(">", i, end="")
    

    还值得注意的是,你的生成器表达式在这里什么都不做,所以我把它删除了。

    【讨论】:

    • 是的,我知道with ...: 存在。问题是文档中提到了这一点:-> 另外,如果超出范围,为什么我不能依靠它自动关闭?
    • @hochl 没有关于垃圾收集如何在 Python 中工作的规范。 CPython 通过引用计数来做到这一点,但其他实现可以用其他方式做到这一点,产生不同的结果。如果您遇到异常,这也可能意味着文件无法正确关闭。然而,最大的原因是可读性。 with 语句使您明确关闭文件,这更具可读性且不易出错。
    • @hochl,因为当对象超出范围时,您期望会发生什么?还活着?它被标记为销毁和文件,关闭它是生命周期过程的一部分。
    • 现在我觉得问起来很笨,但我的脑袋最近一定是垃圾收集了这些知识......
    【解决方案2】:

    this answer。您不保留对文件对象的引用,因此在循环运行后它没有对它的引用。然后它被垃圾收集,当这种情况发生时,文件被关闭。但是,不能保证它会在循环后立即被垃圾收集。在 Python 注意到它没有被使用之前,它可能会存在一段时间。因此,最好显式关闭文件,或者甚至更好地使用 with 块,以便为您关闭它。

    【讨论】:

    • 对了!有趣的是,所有测试用例都立即关闭了文件,但这种行为纯属巧合,不能保证。猜猜这两个答案都会被接受。
    • 对,它可能总是为你做,但关键是你不能依赖它为其他人工作,可能运行不同版本的 Python(也许未来的版本不会'还不存在)。
    • 您的测试用例大概都是在 CPython 中运行的,由于引用计数 GC,它总是会立即关闭。在其他实现中,它会有很大的不同。删除对象是为了释放空间,如果你用它来做其他事情,这是个坏主意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    相关资源
    最近更新 更多