with open('com1', 'r') as f:

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sun Apr 5 02:24:27 EDT 2009


On Sun, 05 Apr 2009 15:51:31 +1200, Lawrence D'Oliveiro wrote:

> All Python objects are reference-counted. Once the file object becomes
> inaccessible, it is automatically closed. Simple.

If only it were so simple.

Firstly, what you describe is an implementation detail of CPython, not 
Python the language. Jython does not close files as soon as they become 
inaccessible, and IronPython and CLPython may not.

Secondly, even in CPython things may not be so simple. Not all file-like 
objects are built-in file objects.

>>> class MyFile(file):
...     pass
...
>>> f = MyFile("test", "r")
>>> n = f.fileno()
>>> os.read(n, 1)
'h'
>>> f.close()
>>> os.read(n, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor

My file-like object works just like the built-in file object, but now I 
can do this:

>>> f = MyFile("test", "r")
>>> f.attr = f  # make a reference cycle
>>> n = f.fileno()
>>> del f
>>> os.read(n, 5)
'hello'

And lo and behold, the file is *not* automatically closed when f becomes 
inaccessible. I don't believe the garbage collector will free that file 
descriptor, possibly not even when Python exists. But watch this:

>>> os.close(n)  # just to be sure
>>>
>>> from __future__ import with_statement
>>> with MyFile("test", "r") as f:
...     n = f.fileno()
...     f.attr = f  # make a reference cycle
...
>>> os.read(n, 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor


The with statement guarantees[1] closing, even if there are other 
references to the file object elsewhere.






[1] Guarantee void if the file system can't actually close the file for 
some reason.


-- 
Steven



More information about the Python-list mailing list