Is the file closed?

I regularly see this code:

filecontent = open(thefilename).read() 

I wonder what will become the file created by open in this situation: is it implicitly closed or remains open somewhere?

+4
source share
1 answer

I wonder what will become the file created open in this situation: is it implicitly closed or is it somewhere open?

It remains open until the garbage collector discovers that no one else can access it and destroys it, after which it is closed by the destructor.

The Python language makes no guarantees as to when this will happen (except, of course, that it will be after you can no longer access it).

However, the CPython implementation (which you probably use because it is the only working 3.x implementation as of May 2013) uses link counting (plus a loop detector) to collect garbage, which means that as soon as the last link leaves (if at some point, she did not participate in the cycle), the object is destroyed.

So, in CPython in most cases the file will be closed, as soon as you return from the function, assign a new value to filecontent or del filecontent . And it relies on a lot of quick and dirty code.

But Jython and IronPython rely on the Java / .NET garbage collector, which periodically checks for garbage in complex and bizarre ways, rather than tracking it on the fly, so there is no guarantee that when something will be collected. And PyPy has several options, depending on how it is configured.

And even in CPython, it is possible that the garbage will remain around after there are no visible links, because, for example, you started it in the debugger and ended up with some invisible links. Or, if the file was involved in the reference loop, it can never close.

Thus, you should not rely on this behavior in everything except fast and dirty code. Basically, if it's acceptable for the file to remain open until your program finishes, it's fine. Otherwise, do not do this.

The correct way to do this is with the with statement:

 with open(thefilename) as f: filecontent = f.read() 

This ensures that f.close() is called as soon as the with statement ends.

Every so often, people offer a way to turn this into a single liner, which Guido always answers with something like: " with open(thefilename) as f: filecontent = f.read() already one-liner. And this is bad, but nowhere so bad as you suggest. "

But actually there is an even better answer: write a function that wraps it:

 def read_whole_file(filename): with open(thefilename) as f: return f.read() 

And then:

 filecontent = read_whole_file(thefilename) 

Clean, concise, readable ... there is no excuse for " open " em all and let the GC sort the "em out" hack.

+12
source

Source: https://habr.com/ru/post/1479417/


All Articles