1

Let's assume I have a file test.txt and want to print the contents. I could do it like this in Python (this is just an example to illustrate my question, not an example of good code):

for i in (line for line in open('test.txt')):
    print ">", i,

I used strace to make sure that the file is opened and closed after the code has executed.

The question: Why is the file closed? I guess it has something to do with context managers, but I can't find any reference to this kind of construct and why the file gets automatically closed. Who knows what happens exactly behind the scenes and can explain it?

hochl
  • 12,524
  • 10
  • 53
  • 87

2 Answers2

4

When a reference to a file goes out of scope, it is garbage collected, and closed as part of being deleted. As you don't assign the file to a name, as soon as the loop ends, it goes out of scope. This, however, is not a good thing to rely upon. Use an actual context manager instead, e.g:

with open('test.txt') as f:
    for i in f:
        print(">", i, end="")

It's also worth noting your generator expression does nothing here, so I've removed it.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • Yes, I know that `with ...:` exists. The question is where this is mentioned in the docs :-> Also, why can't I rely on it being automatically closed if it goes out of scope? – hochl Aug 22 '12 at 17:33
  • @hochl There is no specification as to how garbage collection has to work in Python. CPython does it by reference counting, but other implementations could do it in other ways, producing different results. It could also mean the file doesn't get close correctly if you have an exception. The biggest reason, however, is readability. The `with` statement makes your closing of the file explicit, which is much more readable and less error prone. – Gareth Latty Aug 22 '12 at 17:35
  • @hochl, because what do you expect to happen when an object goes out of scope? Remain alive? It gets marked for destruction and for a file, closing it is part of the life cycle process. – Apprentice Queue Aug 22 '12 at 17:35
  • Now I feel dumb for asking, but my head must have garbage collected this knowledge recently ... – hochl Aug 22 '12 at 17:44
1

See this answer. You don't keep a reference to the file object, so after the loop runs it has no references to it. It is then garbage collected, and when this happens, the file is closed. However, there's no guarantee that it will be garbage collected right away after the loop. It could sit around for a while before Python notices that it's not used. Because of this, it's better to explicitly close the file, or, even better, use a with block so it gets closed for you.

Community
  • 1
  • 1
BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • Ah right! It's interesting that all test cases have closed the file immediately, but then this behaviour is just pure coincidence and not guaranteed. Guess both answers would quality for acceptance. – hochl Aug 22 '12 at 17:38
  • Right, it may always do it for you, but the point is that you can't rely on it working for someone else, possibly running a different version of Python (maybe a future version that doesn't exist yet). – BrenBarn Aug 22 '12 at 17:39
  • 1
    Your test cases are presumably all run in CPython, which will always close straight away due to the reference counting GC. In other implementations, it'll vary massively. Deleting objects is done to free up space, if you are using it to do something else, it's a bad idea. – Gareth Latty Aug 22 '12 at 17:40