Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

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?

like image 637
Brent Newey Avatar asked Dec 02 '09 17:12

Brent Newey


People also ask

Does Python automatically closes a file?

Within the block of code opened by “with”, our file is open, and can be read from freely. However, once Python exits from the “with” block, the file is automatically closed.

Does with automatically close file?

Using a with open() statement will automatically close a file once the block has completed. Not only will using a context manager free you from having to remember to close files manually, but it will also make it much easier for others reading your code to see precisely how the program is using the file.

Is it mandatory to call the close () method after using the file?

Any operation, which requires that the file be opened will raise a ValueError after the file has been closed. Calling close() more than once is allowed. Python automatically closes a file when the reference object of a file is reassigned to another file. It is a good practice to use the close() method to close a file.


2 Answers

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.

like image 127
Tomek Szpakowicz Avatar answered Sep 23 '22 00:09

Tomek Szpakowicz


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  
like image 36
hughdbrown Avatar answered Sep 22 '22 00:09

hughdbrown