Does a File Object Automatically Close when its Reference Count Hits Zero?

Question:

I was under the impression that file objects are immediately closed when their reference counts hit 0, hence the line:

foo = open('foo').read()

would get you the file’s contents and immediately close the file. However, after reading the answer to Is close() necessary when using iterator on a Python file object I get the impression that this does not happen, and that calling .close() on a file object is always necessary.

Does the line above do what I think it’s doing and even if it does, is it the Pythonic thing to do?

Asked By: Brent Newey

||

Answers:

If you want to be sure, I’d write the code like this:

from __future__ import with_statement

with open('foo') as f:
    foo = f.read()

That way, your file closes as expected, even with exceptions.


Much later: here is some code with import dis to show how the compiler treats these differently.

>>> 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 
Answered By: hughdbrown

No, Python optimize deleting unused objects so It may never close your file (OK at the end of your script at exit it will cleanup).
@ hughdbrown have pointed out nice solution.

Answered By: przemo_li

The answer is in the link you provided.

Garbage collector will close file when it destroys file object, but:

  • you don’t really have control over when it happens.

    While CPython uses reference counting to deterministically release resources
    (so you can predict when object will be destroyed) other versions don’t have to.
    For example both Jython or IronPython use JVM and .NET garbage collector which
    release (and finalize) objects only when there is need to recover memory
    and might not do that for some object until the end of the program.
    And even for CPython GC algorithm may change in the future as reference counting
    isn’t very efficient.

  • if exception is thrown when closing file on file object destruction,
    you can’t really do anything about it because you won’t know.

Answered By: Tomek Szpakowicz

For the cpython implementation of python: yes, it is guaranteed to be closed when its reference count goes to zero.

For python as an abstract language (e.g., including Jython, IronPython, etc): no, it is not guaranteed to be closed. In particular, an implementation of Python may choose not to use reference counting, but to use some other form of GC.

References:

Answered By: Edward Loper
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.