1行のコードでファイルを開いて読み取り、閉じる


128

今私は使用します:

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

しかし、コードの見栄えを良くするには、次のようにします。

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

上記の構文を使用する場合、ファイルを閉じてシステムリソースを解放するにはどうすればよいですか?


19
ワンライナーについて本質的に魅力的なものはありません。コードは書かれているよりもはるかに頻繁に読み取られ、「クールさ」ではなく、理解のために書かれるべきです。唯一の例外は、言語によく知られているイディオムがある場合ですが、この場合はわかりません。
drdwilcox

17
@drdwilcox:不可解なワンライナーは悪いですが、宣言的なワンライナーは良いです。理由はありません(少なくとも1つは表示されません)。1回の関数呼び出しでファイル(そのような一般的なニーズ)を読み取るためのコアに関数ラッパーがないのはなぜですか。のようなものcontents = os.readfile(path)。もっとおもしろいことをしたいのなら、OKを使ってくださいwith open(path) as fd: contents = fd.read()。もちろん、独自のラッパーを作成することもできますが、それがコアの目的であり、プログラマーに抽象化に役立つ機能を提供します。
tokland 2013

5
コードが書き込まれるよりもはるかに多く読み取られることは事実ですが、長いコードが短いコードと同じくらい優れているということは、それ以上の間違いはありません。コードをできるだけ短くするために時間を費やした場合(理解しにくい巧妙なトリックに頼らずに)、その投資はコードが読み取られたときに何度も報われます。あなたが書くすべての行はあなたのコードを読んでいる誰にとっても邪悪ですので、できるだけ少なく書くように努めるべきです。パスカルの有名な引用を覚えておいてください:「私はこの手紙を短くする余裕がなかったという理由だけでこの手紙を長くしました。」
ジョンウィリアムズ

回答:


195

あなたは本当にそれを閉じる必要はありません-Pythonはガベージコレクションの間かプログラムの終了時に自動的にそれをします。しかし、@ delnanが述べたように、さまざまな理由で明示的に閉じることをお勧めします。

だから、あなたはそれを短く、シンプルで明示的に保つために何ができるか:

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

今では2行でかなり読みやすいと思います。


2
@ 1qazxsw2 withステートメントを使用する、ファイルリソースは適切に閉じられます。
David Alber

13
最初の文について:Pythonは最終的にそれを閉じます。しかし、それはあなたが閉店を忘れるべきだという意味ではありません。refcountingを使用しても、ファイルは、思ったよりもずっと長く開いたままになることがあります(たとえば、サイクルによって参照される場合)。まともなGCを持つPython実装では、これは3回行われます。特定の時間にGCが行われる保証はありません。CPythonのドキュメントでさえ、このようなクリーンアップのためにGCに依存すべきではないと述べています。答えの後半は太字である必要があります。

6
本当に1行が必要な場合は、のoutput = f.read()後の同じ行にパーツを配置でき:ます。
Karl Knechtel

1
「コードの1行でファイルを開いて読み取り、閉じる」これは2行であり、質問には答えません。
user5359531

1
これは実装に依存します-Svenの回答を参照してください。
Tim Pietzcker

71

Python標準ライブラリPathlibモジュールはあなたが探していることをします:

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

パスをインポートすることを忘れないでください:

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'

Python 27にバックポートpathlibまたはpathlib2


8
提案されてwithいる他の回答は問題withありませんが、表現ではなく声明です。このpathlib回答は、Python式に埋め込むことができる元の質問に対する唯一の回答です。何かSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael

24

CPythonを使用すると、ファイルオブジェクトはすぐにガベージコレクションされるため、行が実行された直後にファイルが閉じられます。ただし、次の2つの欠点があります。

  1. CPythonとは異なるPythonの実装では、多くの場合、ファイルはすぐには閉じられず、後で、制御できないほど閉じられます。

  2. Python 3.2以降ではResourceWarning、有効にするとがスローされます。

1行追加するほうがよい:

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

これにより、すべての状況でファイルが正しく閉じられます。


17

これを行うために特別なライブラリをインポートする必要はありません。

通常の構文を使用すると、ファイルを読み取り用に開いて閉じます。

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

または

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

これにより、行を含む配列xが得られ、次のように出力できます。

for line in x: print line

これらのワンライナーはメンテナンスに非常に役立ちます-基本的に自己文書化。


8

できることは、withステートメントを使用して、2つのステップを1行で記述します。

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

with文では、コールに世話をする__exit__何か悪いが、あなたのコード内で起こった場合でも、指定されたオブジェクトの機能。try... finally構文に近いです。によって返されるオブジェクトの場合open__exit__ファイルクロージャに対応します。

このステートメントはPython 2.6で導入されました。


小さな明確化:に従ってドキュメントは with Pythonの2.5で導入されたが、されなければならなかった明示的にインポートから__future__。Python 2.6のすべてのコンテキストから利用できるようになりました。
デビッドアルバー

5

ilioを使用:(インラインio):

ファイルopen()、read()、close()の代わりに1つの関数呼び出しのみ。

from ilio import read

content = read('filename')

2
with open('pagehead.section.htm')as f:contents=f.read()

4
これは上位3つの回答とどのように違うのですか?
すべての労働者は必須です2016

4
最大の違いは、指定された質問として1行のみであることです。個人的にはそれ以上のものを見つけることはできませんが、実際に質問に自分で貢献するのではなく、自分の作品を自由に批評してください。

3
Pythonでファイルを開いたり、読み込んだり、閉じたりするための組み込みの最短の方法は、1行に圧縮されているかどうかに関係なく、2つの論理行を使用することです。したがって、この答えが3つの元の答えと実質的に異なるとは思わない。
すべての労働者は必須

1
その「実質的に」異なるかどうかは問題ではありません。python -cコマンドラインで使用できる1行の構文を探すためにこのページにたどり着いたため、2行の回答を投稿しても役に立ちません。
user5359531

1
@ user5359531要点がわかりません:でpython式を引用し";2つの命令を追加し、後に改行を削除できることをご存知:ですか?次の表現は私にとってはうまく機能します。$> python -c "with open('some file', 'r') as f: print(next(f))"
JoëlJun

2

これを実現する最も自然な方法は、関数を定義することだと思います。

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

次に、次の操作を実行できます。

output = read('pagehead.section.htm')

0

ログファイルでgreppedしたものを囲む数行を取得する必要があるとき、私は頻繁に次のようなことをします。

$ 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

1
元のトピックとはまったく関係ありませんがgrep -A <n>、役立つ場合は、、、grep -B <n>およびgrep -C <n>を調べる必要があります。詳細:stackoverflow.com/a/9083/1830159
Liam Stanley、

0

を使用more_itertools.with_iterするとoutput、1行で同等のものを開く、読み取る、閉じる、割り当てることができます(importステートメントを除く)。

import more_itertools as mit


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

可能ではありますが、ファイルの内容を変数に割り当てる以外の別のアプローチ、つまり遅延反復を探します。これは、従来のwithブロックを使用するか、上記の例でを削除join()して反復することで実行できますoutput


ワンライナー内にもインポートできます。"".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))これは問題なく機能し、インポートのためのラインが不要になります。
melwil 2017

1
まったく同感です。ただし、onelinersを使用してタスクの解決について議論しているときに、合意された結果が新しいPythonシェルに貼り付けられた1行のコードであるという議論にしばしば気づきました。このような課題は、pep8に準拠することはほとんどありません。コードを書くための良い習慣ではありません。インポートの必要性を取り除くためのヒントとしてのみ意図されていました。
melwil 2017

0

暖かくてぼんやりとした感じがしたい場合は、一緒に行ってください

Python 3.6の場合、私はこれら2つのプログラムをIDLEの新規開始時に実行し、以下のランタイムを提供しました。

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

それほど大きな違いはありません。

#--------*---------*---------*---------*---------*---------*---------*---------*
# 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

出力:

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

出力:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.