• 6
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

name Punditsdkoslkdosdkoskdo

open read and close a file in 1 line of code

Now I use:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

But to make the code look better, I can do:

output = open('pagehead.section.htm','r').read()

When using the above syntax, how do I close the file to free up system resources?

      • 2
    • There is nothing inherently more attractive about one-liners. Code is read far more often than it is written, and should be written for comprehension, not for "coolness." The only exception is when there is a well-known idiom in a language, but I am unaware of one in this case.
    • @drdwilcox: Cryptic one-liners are bad, declarative one-liners are good. There is no reason (at least I cannot see one), why there is no function wrapper in the core to read a file (such common need) in a single function call. Something like contents = os.readfile(path). If I wanted to do something fancier, then ok, I'd happily use with open(path) as fd: contents = fd.read(). Of course one can write its own wrapper, but that's what the core is for, to provide the useful to abstractions to programmers.
    • It's true that code is read far more than it's written, but the implication that longer code is just as good as short code couldn't be more wrong. If you invest time in making your code as short as possible (without resorting to clever tricks that are hard to understand), that investment will pay off over and over when the code is read. Every line you write is a disservice to anyone reading your code, so you should strive to write as little as possible. Remember the famous quote from Pascal: "I made this letter longer only because I have not had the leisure to make it shorter."

You don't really have to close it - Python will do it automatically either during garbage collection or at program exit. But as @delnan noted, it's better practice to explicitly close it for various reasons.

So, what you can do to keep it short, simple and explicit:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Now it's just two lines and pretty readable, I think.

  • 194
Reply Report
    • Re first sentence: Python will close it eventually. But that doesn't mean you should forget about closing. Even with refcounting, the file may stay open far longer than you think and want (e.g. if it happens to be referred to by cycles). This goes thrice in Python implementations that have a decent GC, where you have no guarantee that anything is GC'd at any particular time. Even the CPython documentation says you shouldn't rely on GC for cleanup like this. The latter part of the answer should be bold.
    • If you really need a one-liner, it is possible to put the output = f.read() part on the same line after the :.

Python Standard Library Pathlib module does what you looking for:

Path('pagehead.section.htm').read_text()

Don't forget to import Path:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

On Python 27 install backported pathlib or pathlib2

  • 71
Reply Report
    • The other answers proposing with are fine, but with is a statement, not an expression. This pathlib answer is the only reply to the original question that can be embedded in a Python expression. Something like SECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()

Using CPython, your file will be closed immediately after the line is executed, because the file object is immediately garbage collected. There are two drawbacks, though:

  1. In Python implementations different from CPython, the file often isn't immediately closed, but rather at a later time, beyond your control.

  2. In Python 3.2 or above, this will throw a ResourceWarning, if enabled.

Better to invest one additional line:

with open('pagehead.section.htm','r') as f:
    output = f.read()

This will ensure that the file is correctly closed under all circumstances.

  • 24
Reply Report

No need to import any special libraries to do this.

Use normal syntax and it will open the file for reading then close it.

with open("/etc/hostname","r") as f: print f.read() 

or

with open("/etc/hosts","r") as f: x = f.read().splitlines()

which gives you an array x containing the lines, and can be printed like so:

for line in x: print line

These one-liners are very helpful for maintenance - basically self-documenting.

  • 17
Reply Report

What you can do is to use the with statement, and write the two steps on one line:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

The with statement will take care to call __exit__ function of the given object even if something bad happened in your code; it's close to the try... finally syntax. For object returned by open, __exit__ corresponds to file closure.

This statement has been introduced with Python 2.6.

  • 8
Reply Report
with open('pagehead.section.htm')as f:contents=f.read()
  • 2
Reply Report
      • 2
    • The biggest difference is that it is only one line as the question specified. Personally I can't find any beyond that but feel free to critique my work rather than actually contributing to the question yourself.
    • The shortest, built-in way to achieve opening, reading, and closing a file in Python is using 2 logical lines whether it's condensed down to 1 line or not. So I don't see this answer to be effectively any different from the 3 original answers.
      • 2
    • It does not matter if its 'effectively' different. I got to this page looking for one-line syntax that might be used with python -c on the command line, so posting 2-line answers does not help.
      • 2
    • @user5359531 I don't see your point: do you know that you can quote python expressions with ", use ; to append two instructions, and delete newline after : ? Following expression works just fine for me : $> python -c "with open('some file', 'r') as f: print(next(f))"

I think the most natural way for achieving this is to define a function.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Then you can do the following:

output = read('pagehead.section.htm')
  • 2
Reply Report

I frequently do something like this when I need to get a few lines surrounding something I've grepped in a log file:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
  • 0
Reply Report

Using more_itertools.with_iter, it is possible to open, read, close and assign an equivalent output in one line (excluding the import statement):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Although possible, I would look for another approach other than assigning the contents of a file to a variable, i.e. lazy iteration - this can be done using a traditional with block or in the example above by removing join() and iterating output.

  • 0
Reply Report
      • 2
    • I completely agree with you. However while discussing solving tasks with oneliners, I've often found myself in arguments where the agreed outcome should be a single line of code pasted into a fresh python shell. Such challenges rarely conform to pep8. It's in no way a good practice for writing code, it was only meant as a tip to remove the need for imports.
      • 1
    • You can import inside the oneliner as well. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r"))) This works just fine, and eliminates the need for a line for the import.

If you want that warm and fuzzy feeling just go with with.

For python 3.6 I ran these two programs under a fresh start of IDLE, giving runtimes of:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

So not much of a difference.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

OUTPUT:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

OUTPUT:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
  • 0
Reply Report

Trending Tags