tags:

views:

194

answers:

7

In Ruby you can read from a file using s = File.read(filename). The shortest and clearest I know in Python is

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

Is there any other way to do it that makes it even shorter (preferably one line) and more readable?

Note: initially I phrased the question as "doing this in a single line of code". As pointed by S.Lott, shorter doesn't necessary mean more readable. So I rephrased my question just to make clear what I meant. I think the Ruby code is better and more readable not necessarily because it's one line versus two (though that matters as well), but also because it's a class method as opposed to an instance method, which poses no question about who closes the file, how to make sure it gets closed even if an exception is raised, etc. As pointed in the answers below, you can rely on the GC to close your file (thus making this a one-liner), but that makes the code worse even though it's shorter. Not only by being unportable, but by making it unclear.

+4  A: 

This is same as above but does not handle errors:

s = open(filename, 'r').read()
pyfunc
Not really, yours leaves the file open.
ionut bizau
The CPython implementation does close the file when the reference count goes to zero, but that is an implementation detail that shouldn't be relied on.
Mark Tolonen
This does handle errors; an exception will be thrown as usual. This does *not* "leave the file open", but what it may do is cause the file close to be *delayed* depending on the GC implementation. That can be a problem (locking in Windows, and eg. FD limits if looping over many files), but that's very different from leaving the file open (eg. leaking the file).
Glenn Maynard
@Glenn Maynard: Theoretically closing can be delayed until termination of the process, and in the meantime, the open file could leak (for instance to subprocesses in case of a `fork()`).
lunaryorn
There are lots of ways that can happen; for example, objects keeping an sqlite db open; a PRNG module keeping /dev/urandom open, and so on. It's a very good idea to close files explicitly, and there are issues like these to keep in mind if you don't, but a GC-delayed close isn't a leak.
Glenn Maynard
It is portable enough for the scope of "I want it one line long" without requiring overengineering lessons ("you can port your oneliner to Jython")
piro
If your design goal is "one line of code", you've inhaled too much Perl and you need to schedule some serious un-brainwashing time.
Glenn Maynard
My goal is not using a one-liner, that's why I would never accept this solution, even though it's probably fine in most cases on most implementations. It's just confusing, for me and for others.
ionut bizau
No, this isn't confusing in the slightest.
Glenn Maynard
A: 
contents = open(filename).read()
ars
And when do you close the file?
ionut bizau
@ionut bizau - When the return of `open(...)` is garbage collected, I think. Someone correct me if I'm wrong.
detly
+5  A: 
with file('x.py') as f: s = f.read()

***grins***

Mark Tolonen
Upvoted for trying to be funny. Not marking as accepted though. :))
ionut bizau
awwwwwwwwww ;^)
Mark Tolonen
A: 

Slow, ugly, platform-specific... but one-liner ;-)

import subprocess

contents = subprocess.Popen('cat %s' % filename, shell = True, stdout = subprocess.PIPE).communicate()[0]
eumiro
aaaaaaaaaaargh! (excess 'a's to meet min char limit)
Peter Gibson
Certainly matches the spirit of the question... perverse use of Python to make it resemble Bash is no worse than making it resemble Ruby or Perl.
detly
A: 
contents = open(filename)

This gives you generator so you must save somewhere the values though, or

contents = [line for line in open(filename)]

This does the saving to list explicit close is not then possible (at least with my knowledge of Python).

Tony Veijalainen
why no need to close?
aaronasterling
and with contents = ''.join(line for line in open(filename)) you have the original file contents...
eumiro
Using a file as an iterator does *not* close the file deterministically (like `with` does). It can't, because after iteration finishes, it's still valid to seek the file and start reading again, which wouldn't work if iteration closed the file.
Glenn Maynard
@Glenn But if you use the generator in list comprehension like my example, it is not even possible to close it as it has not name.
Tony Veijalainen
"Not being able to close it" is *not* the same as "don't need to close it".
Glenn Maynard
Maybe so but you I would not know how to access that file handle from inside list comprehension. Should be maybe 'finished all file i/o, close all program opened file' command in Python? Or maybe explicit gc for file objects would be enough? The file handle is though out of scope as list comprehension is separate scope.
Tony Veijalainen
+3  A: 

This isn't Perl; you don't want to force-fit multiple lines worth of code onto a single line. Write a function, then calling the function takes one line of code.

def read_file(fn):
    """
    >>> import os
    >>> fn = "/tmp/testfile.%i" % os.getpid()
    >>> open(fn, "w+").write("testing")
    >>> read_file(fn)
    'testing'
    >>> os.unlink(fn)
    >>> read_file("/nonexistant")
    Traceback (most recent call last):
        ...
    IOError: [Errno 2] No such file or directory: '/nonexistant'
    """
    with open(fn) as f:
        return f.read()

if __name__ == "__main__":
    import doctest
    doctest.testmod()
Glenn Maynard
+2  A: 

If you're open to using libraries, try installing forked-path (with either easy_install or pip).

Then you can do:

from path import path
s = path(filename).bytes()

This library is fairly new, but it's a fork of a library that's been floating around Python for years and has been used quite a bit. Since I found this library years ago, I very seldom use os.path or open() any more.

ma3
Looks like a nice library. I won't install it just for this, but I'll have it in mind.
ionut bizau