「while not EOF」のためのPythonの完璧な対応物は何ですか


114

CまたはPascalでテキストファイルを読み取るには、次のスニペットを使用して、EOFまでデータを読み取ります。

while not eof do begin
  readline(a);
  do_something;
end;

したがって、Pythonでこれを簡単かつ高速に実行するにはどうすればよいのでしょうか。

回答:


189

ファイルをループして行を読み取ります。

with open('somefile') as openfileobject:
    for line in openfileobject:
        do_something()

ファイルオブジェクトは反復可能で、EOFまで行を生成します。ファイルオブジェクトをイテラブルとして使用すると、バッファーを使用して確実に読み取りを実行できます。

stdinでも同じことができます(使用する必要はありませんraw_input()

import sys

for line in sys.stdin:
    do_something()

画像を完成させるために、バイナリ読み取りは次のように実行できます。

from functools import partial

with open('somefile', 'rb') as openfileobject:
    for chunk in iter(partial(openfileobject.read, 1024), b''):
        do_something()

chunkは、ファイルから一度に最大1024バイトが含まれ、openfileobject.read(1024)空のバイト文字列を返し始めると反復が停止します。


4
注:のline末尾には改行文字があります。
ben_joseph 2017

1
多分あなたは6GiB長いラインを持っているので、ラインを読むことは...、汎用的なバイナリファイルのビット危険である
LtWorf

@LtWorf:バイナリファイル行ではなくチャンクで読み取る方法を示すのはこのためです。
Martijn Pieters

stdin実行中のプロセスからを読み取っています...そのため、プロセスを強制終了するまで、EOFはありません。しかし、それから私は「これまでのところ」に達し、私は行き詰まります。デッドロックではなく、これをどのように検出しますか?新しい行がないかのように、ファイルの読み取りを停止します(EOFがない場合でも、私の場合は存在しません)。
チャーリーパーカー、

@CharlieParker:デッドロックに達した場合、おそらく何かがバッファをフラッシュするのを忘れています。実際のMCVEがなければ、それ以上のことを言うのは難しいです。
Martijn Pieters

61

PythonでCイディオムを模倣できます。

max_sizeバイト数までのバッファーを読み取るには、次のようにします。

with open(filename, 'rb') as f:
    while True:
        buf = f.read(max_size)
        if not buf:
            break
        process(buf)

または、テキストファイルを1行ずつ:

# warning -- not idiomatic Python! See below...
with open(filename, 'rb') as f:
    while True:
        line = f.readline()
        if not line:
            break
        process(line)

eofテストwhile True / breakないため、構成を使用する必要がありますPythonには、読み取りから返されたバイトが不足していること以外に。

Cでは、次のようになります。

while ((ch != '\n') && (ch != EOF)) {
   // read the next ch and add to a buffer
   // ..
}

ただし、Pythonではこれを使用できません。

 while (line = f.readline()):
     # syntax error

式では代入が許可されていないためPythonのでです(ただし、最近のバージョンのPythonは代入式を使用してこれを模倣できますが、以下を参照してください)。

これを行うことは、Pythonでは確かにより慣用的です。

# THIS IS IDIOMATIC Python. Do this:
with open('somefile') as f:
    for line in f:
        process(line)

更新: Python 3.8以降では、割り当て式も使用できます。

 while line := f.readline():
     process(line)

@MartijnPieters:今はそうです:-)
dawg

3
CおよびPerlプログラマーとして、式で代入が許可されないというあなたの指摘私にとって重要でした。
CODE-REaD 2016年

1
"while True:"メソッドは、反復ごとに複数の入力行を操作する必要がある場合にも役立ちます。これは、慣用的なPythonでは(とにかく)許可されていないものです。
ドナルドスミス

ファイルを想定していない場合は、行を読んではいけません。バイナリファイルには大きな行がある可能性があります...
LtWorf

非慣用的readline()な方法には利点があるようです:キャッチなどのきめ細かなエラー処理UnicodeDecodeErrorを実行できますが、慣用的なfor反復では実行できません。
flow2k

17

ファイルを開いて行ごとに読み取るためのPythonイディオムは次のとおりです。

with open('filename') as f:
    for line in f:
        do_something(line)

上記のコードの最後で、ファイルは自動的に閉じられます(with構成はそれを処理します)。

最後に、line末尾の改行が保持されることは注目に値します。これは、以下を使用して簡単に削除できます。

line = line.rstrip()

1
+1は、これがOPに対して、一般的に提案されているソリューションである非常に類似したと同じではないことも示していfor line in f.readlines(): ...ます。
jedwards 2013年

12

以下のコードスニペットを使用して、ファイルの終わりまで、行ごとに読み取ることができます

line = obj.readline()
while(line != ''):

    # Do Something

    line = obj.readline()

1
IMO、これは質問された内容を最もよく反映する1つの回答です。
gvrocha 2017

行を繰り返し処理すると、プログラムの構造が歪むことがよくあります。たとえば、言語パーサーで、行を読み取って順番に処理したいとします。読み取り行をループしてパーサーに送信できるように、トップレベルを再構築する必要はありません。
Jonathan Starr

11

上記の「Pythonの方法で実行する」ための提案がありますが、EOFに基づくロジックを実際に使用したい場合は、例外処理を使用する方法だと思います-

try:
    line = raw_input()
    ... whatever needs to be done incase of no EOF ...
except EOFError:
    ... whatever needs to be done incase of EOF ...

例:

$ echo test | python -c "while True: print raw_input()"
test
Traceback (most recent call last):
  File "<string>", line 1, in <module> 
EOFError: EOF when reading a line

またはを押してCtrl-Zraw_input()プロンプト(Windowsの、Ctrl-ZLinuxの)


@TessellatingHecklerは、ドキュメントに書かれているものとは異なります。「組み込み関数(input()またはraw_input())のいずれかが、データを読み取らずにファイルの終わり条件(EOF)に達したときに発生します。」
Tadhg McDonald-Jensen

1
@ TadhgMcDonald-Jensenねえ、そうでしょう。なんて変だ。虚偽の申し立てが撤回され、不当な反対投票が削除されました。
TessellatingHeckler

1

次のコードスニペットを使用できます。readlines()は、ファイル全体を一度に読み取り、行ごとに分割します。

line = obj.readlines()

0

@dawgのすばらしい答えに加えて、walrus演算子(Python> = 3.8)を使用した同等のソリューション:

with open(filename, 'rb') as f:
    while buf := f.read(max_size):
        process(buf)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.