Apa pasangan yang sempurna dalam Python untuk "sementara bukan EOF"

115

Untuk membaca beberapa file teks, dalam C atau Pascal, saya selalu menggunakan cuplikan berikut untuk membaca data hingga EOF:

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

Jadi, saya bertanya-tanya bagaimana saya bisa melakukan ini secara sederhana dan cepat dengan Python?

Allen Koo
sumber

Jawaban:

191

Ulangi file untuk membaca baris:

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

Objek file iterable dan menghasilkan baris sampai EOF. Menggunakan objek file sebagai iterable menggunakan buffer untuk memastikan kinerja membaca.

Anda dapat melakukan hal yang sama dengan stdin (tidak perlu menggunakan raw_input():

import sys

for line in sys.stdin:
    do_something()

Untuk melengkapi gambaran, pembacaan biner dapat dilakukan dengan:

from functools import partial

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

di mana chunkakan berisi hingga 1024 byte sekaligus dari file, dan iterasi berhenti ketika openfileobject.read(1024)mulai mengembalikan string byte kosong.

Martijn Pieters
sumber
4
Catatan: Ini lineakan memiliki karakter baris baru di akhir.
ben_joseph
1
Membaca baris agak berbahaya untuk file biner umum, karena mungkin Anda memiliki garis panjang 6GiB…
LtWorf
@LtWorf: itulah sebabnya saya menunjukkan cara membaca file biner dalam potongan daripada baris.
Martijn Pieters
Saya membaca dari stdinproses yang sedang berjalan ... jadi tidak pernah memiliki EOF sampai saya menghentikan prosesnya. Tapi kemudian saya mencapai "akhir sampai sekarang" dan saya menemui jalan buntu. Bagaimana cara mendeteksi ini dan bukan kebuntuan? Seperti jika tidak ada baris baru, berhenti membaca file (bahkan jika tidak ada EOF, yang dalam kasus saya tidak akan pernah ada).
Charlie Parker
@CharlieParker: jika Anda menemui jalan buntu, mungkin ada sesuatu yang lupa untuk membersihkan buffer. Tanpa MCVE yang sebenarnya, sulit untuk mengatakan lebih dari itu.
Martijn Pieters
61

Anda bisa meniru idiom C dengan Python.

Untuk membaca buffer hingga max_sizesejumlah byte, Anda dapat melakukan ini:

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

Atau, file teks baris demi baris:

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

Anda perlu menggunakan while True / breakkonstruksi karena tidak ada pengujian eof dengan Python selain kurangnya byte yang dikembalikan dari pembacaan.

Di C, Anda mungkin memiliki:

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

Namun, Anda tidak dapat menggunakan ini dengan Python:

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

karena tugas tidak diperbolehkan dalam ekspresi dengan Python (meskipun versi terbaru Python dapat meniru ini menggunakan ekspresi tugas, lihat di bawah).

Jelas lebih idiomatis dalam Python untuk melakukan ini:

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

Pembaruan: Sejak Python 3.8 Anda juga dapat menggunakan ekspresi tugas :

 while line := f.readline():
     process(line)
dawg
sumber
@MartijnPieters: Sekarang :-)
dawg
3
Sebagai programmer C dan Perl, poin Anda bahwa tugas tidak diperbolehkan dalam ekspresi sangat penting bagi saya.
CODE-REaD
1
Metode "while True:" juga berguna ketika Anda perlu beroperasi pada lebih dari satu baris masukan per iterasi, sesuatu yang tidak diizinkan oleh idiomatik Python (sejauh yang saya tahu).
Donald Smith
Anda tidak boleh membaca baris jika Anda tidak membuat asumsi pada file. File biner mungkin memiliki baris yang sangat besar…
LtWorf
Tampaknya ada keuntungan dengan cara non-idiomatik readline(): Anda dapat melakukan penanganan kesalahan yang sangat detail, seperti menangkap UnicodeDecodeError, yang tidak dapat Anda lakukan dengan foriterasi idiomatik .
flow2k
17

Idiom Python untuk membuka file dan membacanya baris demi baris adalah:

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

File akan secara otomatis ditutup pada akhir kode di atas ( withkonstruksi menangani itu).

Akhirnya, perlu dicatat bahwa lineakan mempertahankan garis baru yang membuntuti. Ini dapat dengan mudah dihapus menggunakan:

line = line.rstrip()
NPE
sumber
1
+1, juga menunjukkan kepada OP bahwa ini tidak sama dengan sangat mirip for line in f.readlines(): ..., solusi yang biasanya disarankan.
jedwards
12

Anda dapat menggunakan potongan kode di bawah ini untuk membaca baris demi baris, hingga akhir file

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

    # Do Something

    line = obj.readline()
AR
sumber
1
IMO, ini adalah satu jawaban yang paling mencerminkan apa yang ditanyakan.
gvrocha
Seringkali iterasi melewati garis akan merusak struktur program. Misalnya, dalam parser bahasa, Anda ingin membaca baris dan memprosesnya secara berurutan. Anda tidak ingin merestrukturisasi level atas hanya agar Anda dapat mengulang garis bacaan dan kemudian mengirimkannya ke parser.
Jonathan Starr
11

Meskipun ada saran di atas untuk "melakukannya dengan cara python", jika seseorang ingin benar-benar memiliki logika berdasarkan EOF, maka saya kira menggunakan penanganan pengecualian adalah cara melakukannya -

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

Contoh:

$ 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

Atau tekan Ctrl-Zsaat raw_input()diminta (Windows, Ctrl-ZLinux)

pengguna5472996
sumber
@TessellatingHeckler bukan itu yang dikatakan dalam dokumentasi : "Dibesarkan saat salah satu fungsi bawaan (input () atau raw_input ()) mencapai kondisi akhir file (EOF) tanpa membaca data apa pun."
Tadhg McDonald-Jensen
1
@ TadhgMcDonald-Jensen Baiklah, baiklah. Aneh sekali. Klaim palsu dicabut dan suara negatif yang tidak adil dihapus.
TessellatingHeckler
1

Anda dapat menggunakan potongan kode berikut. readlines () membaca seluruh file sekaligus dan membaginya dengan baris.

line = obj.readlines()
Aditeya Pandey
sumber
0

Selain jawaban bagus @ dawg, solusi yang setara menggunakan operator walrus (Python> = 3.8):

with open(filename, 'rb') as f:
    while buf := f.read(max_size):
        process(buf)
Tak terhingga
sumber