当文件对象的引用计数达到零时自动关闭?

Bre*_*wey 37 python

我的印象是文件对象在引用计数达到0时立即关闭,因此该行:

foo = open('foo').read()
Run Code Online (Sandbox Code Playgroud)

会得到文件的内容并立即关闭文件.但是,在Python文件对象上使用迭代器时,在读取了Is close()的答案之后,我得到的印象是这不会发生,并且始终需要调用.close()文件对象.

上面的那行是否符合我的想法,即使它确实如此,它是Pythonic要做的吗?

Tom*_*icz 31

答案在您提供的链接中.

垃圾收集器在销毁文件对象时会关闭文件,但是:

  • 你真的无法控制它何时发生.

    虽然CPython使用引用计数来确定性地释放资源(因此您可以预测对象何时将被销毁),而其他版本则不需要.例如,Jython或IronPython都使用JVM和.NET垃圾收集器,它只在需要恢复内存时释放(并最终确定)对象,并且在程序结束之前可能不会对某些对象执行此操作.即使对于CPython,GC算法在未来可能会发生变化,因为引用计数效率不高.

  • 如果在文件对象销毁时关闭文件时抛出异常,你就无法对它做任何事情,因为你不会知道.


hug*_*own 27

如果你想确定,我会写这样的代码:

from __future__ import with_statement

with open('foo') as f:
    foo = f.read()
Run Code Online (Sandbox Code Playgroud)

这样,即使有例外,您的文件也会按预期关闭.


很久以后:这里有一些代码import dis来展示编译器如何区别对待它们.

>>> def foo(filename):
...     with open(filename) as f:
...         return f.read()
... 
>>> def bar(filename):
...     return open(filename).read()
... 
>>> from dis import dis
>>> 
>>> dis(foo)
  2           0 LOAD_GLOBAL              0 (open)
              3 LOAD_FAST                0 (filename)
              6 CALL_FUNCTION            1
              9 DUP_TOP             
             10 LOAD_ATTR                1 (__exit__)
             13 ROT_TWO             
             14 LOAD_ATTR                2 (__enter__)
             17 CALL_FUNCTION            0
             20 STORE_FAST               1 (_[1])
             23 SETUP_FINALLY           23 (to 49)
             26 LOAD_FAST                1 (_[1])
             29 DELETE_FAST              1 (_[1])
             32 STORE_FAST               2 (f)

  3          35 LOAD_FAST                2 (f)
             38 LOAD_ATTR                3 (read)
             41 CALL_FUNCTION            0
             44 RETURN_VALUE        
             45 POP_BLOCK           
             46 LOAD_CONST               0 (None)
        >>   49 WITH_CLEANUP        
             50 END_FINALLY         
             51 LOAD_CONST               0 (None)
             54 RETURN_VALUE        
>>> dis(bar)
  2           0 LOAD_GLOBAL              0 (open)
              3 LOAD_FAST                0 (filename)
              6 CALL_FUNCTION            1
              9 LOAD_ATTR                1 (read)
             12 CALL_FUNCTION            0
             15 RETURN_VALUE 
Run Code Online (Sandbox Code Playgroud)


Edw*_*per 10

对于python的cpython实现:是的,它保证在引用计数变为零时关闭.

对于python作为抽象语言(例如,包括Jython,IronPython等):不,它不能保证关闭.特别是,Python的实现可能选择不使用引用计数,而是使用其他形式的GC.

参考文献: