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

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?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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.

Method 2

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

Method 3

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:

Method 4

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.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x