6

Consider the following piece of Python (2.x) code:

for line in open('foo').readlines():
    print line.rstrip()

I assume that since the open file remains unreferenced it has to be closed automatically. I have read about garbage collector in Python which frees memory allocated by unused objects. Is GC general enough to handle the files too?

  • Related reading: [Everybody thinks about garbage collection the wrong way](https://blogs.msdn.microsoft.com/oldnewthing/20100809-00/?p=13203). – Daniel Pryden Mar 27 '18 at 12:47

3 Answers3

7

UPDATE

For current versions of python, the clear recommendation is to close files explicitly or use a with statement. No indication anymore that the GC will close the file for you. So now the answer should be: Maybe, but no guarantee. Always use close() or a with statement.

In the Python 3.8 docs the text has been updated to:

If you’re not using the with keyword, then you should call f.close() to close the file and immediately free up any system resources used by it.

Warning: Calling f.write() without using the with keyword or calling f.close() might result in the arguments of f.write() not being completely written to the disk, even if the program exits successfully.

Old Answer:

Taken from the Python 3.6 docs:

If you’re not using the with keyword, then you should call f.close() to close the file and immediately free up any system resources used by it. If you don’t explicitly close a file, Python’s garbage collector will eventually destroy the object and close the open file for you, but the file may stay open for a while. Another risk is that different Python implementations will do this clean-up at different times.

So yes, the file will be closed automatically, but in order to be in control of the process you should do so yourself or use a with statement:

with open('foo') as foo_file:
    for line in foo_file.readlines():
        print line.rstrip()

foo_file will be clsoed once the with block ends

In the Python 2.7 docs, the wording was different:

When you’re done with a file, call f.close() to close it and free up any system resources taken up by the open file. After calling f.close(), attempts to use the file object will automatically fail.

so I assume that you should not depend on the garbage collector automatically closing files for you and just do it manually/use with

FlyingTeller
  • 17,638
  • 3
  • 38
  • 53
  • Interesting the documentation is 3.8 is different (see https://docs.python.org/3.8/tutorial/inputoutput.html) I think it is wrong that it will only get closed when the GC collects it since Python also has ref counting which removes the file object after open(...).read() immediately. They currently still recommend using the with statement (although for other reasons) which I think is a pity since you could do the same with just one line with ref counting. – Nils Dec 14 '20 at 12:10
  • ref counting is named as the "main garbage collection algorithm" in python [see here](https://devguide.python.org/garbage_collector/), so the statement that "it is wrong that it will only get closed when the GC collects it since Python also has ref counting" does not really apply. I would suspect that they removed the GC reference from the docs to further discourage people from relying on the GC collector to close the file – FlyingTeller Dec 14 '20 at 13:11
  • @FlyingTeller, I've added a quote from more recent (Python 3.8-3.10) documentation, which is even stronger than the previous docs. Personally, I think the reference to Python 2.7 could be removed (it's long dead), but I wouldn't take the liberty to go so far and leave that up to you to decide. – wovano Nov 19 '21 at 10:55
  • BTW: this topic became active due to [this question](https://stackoverflow.com/q/70033013/10669875) – wovano Nov 19 '21 at 10:55
  • 1
    @wovano thanks for the update. I think we can leave the 2.7 reference in there for completeness as the original question was about python 2.x specifically. I will edit though to highlight that for current python versions there is no more reference in the docs that indicates that you could go without the `with` statement. The `Python’s garbage collector will eventually destroy the object and close the open file for you` from python 3.6 does no longer apply – FlyingTeller Nov 19 '21 at 11:19
1

I often use open without with so I ran a little test. For the test I use Python 3.9 so I'm not speaking of earlier versions but for 3.9 at least, we do not need the with to have a clean file close.

bash

 inotifywait -m "testfile"

python3.9

 lines=[line for line in open("testfile")]
 sleep(5)
 for line in lines:
    print(line)

Watch the inotifywait window and run the python script. Before the sleep the final event will be CLOSE_NOWRITE,CLOSE and there will be no other events from that file through the run of the python script.

Stephen Boston
  • 971
  • 1
  • 12
  • 23
0

It depends on what you do, check out this description how it works.

In general I would recommend to use the context manager of the file:

with open("foo", "r") as f:
    for line in f.readlines():
    # ....

which is similar to (for basic understanding):

file_context_manager = open("foo", "r").__enter__()
for line in file_context_manager.readlines():
    # ....
file_context_manager.__exit__()

The first version is a lot more readable, and the withstatement calls the exit method automatically (plus a bit more context handling). The file will be closed automatically when the scope of the with statement is left.

RunOrVeith
  • 4,487
  • 4
  • 32
  • 50
  • "which is the same as" is a confusing statement, since the with block will call `__exit__()` in the end, whereas there is no guaranteed cleanup at the end of the for loop – FlyingTeller Mar 27 '18 at 12:45
  • Your second example is very much *not* the same, since you call `__enter__` but never call `__exit__`. – Daniel Pryden Mar 27 '18 at 12:45
  • 2
    The behavior is still not exactly the same. The specification in [PEP 343](https://www.python.org/dev/peps/pep-0343/#specification-the-with-statement) gives the exact translation of what the `with` block expands to, and it's a lot more complicated. – Daniel Pryden Mar 27 '18 at 12:54