tags:

views:

206

answers:

4

Let's say we want to implement an equivalent of the PHP's file_get_content.

What is the best practice? (elegant and reliable)

Here are some proposition, are they correct?

using "with" statement:

def file_get_contents(filename):
    with file(filename) as f:
        s = f.read()
    return s

using is using standard open safe?

def file_get_contents(filename):
    return open(filename).read()

What happens to file descriptor in either solution?

+2  A: 

with will make sure that the file is closed when the block is left.

In your second example, the file handle might remain open (Python makes no guarantee that it's closed or when if you don't do it explicitly).

Aaron Digulla
Not quite. On CPython, the file is closed as soon as the file descriptor goes out of scope - certainly by the time the function returns. (I checked the Python source, as this point came up elsewhere recently.) On IronPython and Jython, the file will get closed when the file object is garbage collected, but there's no guarantees as to when that'll be.
Vinay Sajip
If you don't use `with`, the file is closed even in the case of an exception?
Hank Gay
@Hank Gay: if you don't `with` there are no guarantees -- the OS file descriptor may be left open.
S.Lott
@S.Lott: That doesn't seem to be true (see Vinay's comment).
Aaron Digulla
A: 
import os

def file_get_contents(filename):
  if os.path.exists(filename):
    fp = open(filename, "r")
    content = fp.read()
    fp.close()
    return content

This case it will return None if the file didn't exist, and the file descriptor will be closed before we exit the function.

amrhassan
This misses the point of using `with` - this code has the same weakness as explicit `new/delete` in C++ code - in the event of any intervening exception before the cleanup code, the cleanup just doesn't happen. On earlier Python's, one could wrap this example in `try/catch/finally`, but the cool kids are all using `with`.
Paul McGuire
This misses the point of the question on reliability. It adds unwanted features (check on file existence), and is not particularly elegant (importing os and code length).
vaab
+2  A: 

Using the with statement is actually the nicest way to be sure that the file is really closed.

Depending on the garbage collector behavior for this task might work, but in this case, there is a nice way to be sure in all cases, so...

multani
+9  A: 

In the current implementation of CPython, both will generally immediately close the file. However, Python the language makes no such guarantee for the second one - the file will eventually be closed, but the finaliser may not be called until the next gc cycle. Implementations like Jython and IronPython will work like this, so it's good practice to explicitely close your files.

I'd say using the first solution is the best practice, though open is generally preferred to file. Note that you can shorten it a little though if you prefer the brevity of the second example:

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

The __exit__ part of the context manager will execute when you leave the body for any reason, including exceptions and returning from the function - there's no need to use an intermediate variable.

Brian
from PEP 343: http://www.python.org/dev/peps/pep-0343 Note that we're not guaranteeing that the finally-clause is executed immediately after the generator object becomes unused, even though this is how it will work in CPython. This is similar to auto-closing files: while a reference-counting implementation like CPython deallocates an object as soon as the last reference to it goes away, implementations that use other GC algorithms do not make the same guarantee. This applies to Jython, IronPython, and probably to Python running on Parrot.
kriss
@kriss: Note that that doesn't contradict the statement about running `__exit__` when leaving the body - it just details what happens if you **don't** exit the body by having a generator suspended within the context manager, and how python will force it to leave by raising an exception.
Brian