Care este echivalentul perfect în Python pentru „while not EOF” (Programare, Python, Fișier, Iterație, Eof)

Allen Koo a intrebat.

Pentru a citi un fișier text, în C sau Pascal, folosesc întotdeauna următoarele fragmente pentru a citi datele până la EOF:

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

Astfel, mă întreb cum aș putea face acest lucru simplu și rapid în Python?

7 răspunsuri
Martijn Pieters

Buclați fișierul pentru a citi liniile:

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

Obiectele de fișier sunt iterabile și produc linii până la EOF. Utilizarea obiectului de fișier ca iterabil utilizează un buffer pentru a asigura citiri performante.

Puteți face același lucru cu stdin (nu este nevoie să utilizați raw_input():

import sys

for line in sys.stdin:
    do_something()

Pentru a completa imaginea, citirile binare se pot face cu:

from functools import partial

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

unde chunk va conține până la 1024 octeți la un moment dat din fișier, iar iterația se oprește când openfileobject.read(1024) începe să returneze șiruri de octeți goale.

Comentarii

  • Notă: Funcția line va avea un caracter de linie nouă la sfârșit. –  > Por ben_joseph.
  • Citirea liniilor este un pic periculoasă pentru fișierele binare generice, deoarece poate aveți o linie lungă de 6GiB… –  > Por LtWorf.
  • @LtWorf: de aceea arăt cum se citesc fișierele binare în bucăți mai degrabă decât în linii. –  > Por Martijn Pieters.
  • Eu citesc dintr-un fișier stdin de la un proces în curs de execuție… deci nu are niciodată EOF până când nu omor procesul. Dar apoi ajung la „end up to now” și mă blochez. Cum detectez acest lucru și nu fac deadlock? Cum ar fi dacă nu există linii noi, să nu mai citesc fișierele (chiar dacă nu există un EOF, care în cazul meu nu va exista niciodată). –  > Por Charlie Parker.
  • @CharlieParker: dacă ați ajuns la un deadlock, atunci ceva este probabil uitând să goliți un buffer. Fără un MCVE real, este greu de spus ceva mai mult decât atât. –  > Por Martijn Pieters.
dawg

Puteți imita idiomul C în Python.

Pentru a citi un buffer de până la max_size număr de octeți, puteți face acest lucru:

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

Sau, un fișier text linie cu linie:

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

Trebuie să utilizați while True / break deoarece există o construcție nici un test eof în Python, în afară de lipsa de octeți returnată de la o citire.

În C, ați putea avea:

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

Cu toate acestea, nu puteți avea acest lucru în Python:

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

deoarece atribuțiile nu sunt permise în expresii în Python (deși versiunile recente ale Python pot imita acest lucru folosind expresii de atribuire, a se vedea mai jos).

Cu siguranță este mai mult idiomatic în Python să faci acest lucru:

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

Actualizare: Începând cu Python 3.8, puteți utiliza și expresii de atribuire:

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

Comentarii

  • @MartijnPieters: Acum da 🙂 –  > Por dawg.
  • În calitate de programator C și Perl, punctul tău de vedere că atribuțiile nu sunt permise în expresii a fost crucial pentru mine. –  > Por CODE-REaD.
  • Metoda „while True:” este, de asemenea, utilă atunci când trebuie să operați pe mai mult de o linie de intrare pe iterație, lucru pe care Python-ul idiomatic nu îl permite (din câte îmi dau seama, oricum). –  > Por Donald Smith.
  • Nu ar trebui să citiți liniile dacă nu faceți presupuneri asupra fișierului. Un fișier binar ar putea avea linii imense… –  > Por LtWorf.
  • Se pare că există un avantaj al metodei non-idiomatice readline() mod: puteți face o gestionare fină a erorilor, cum ar fi prinderea de erori. UnicodeDecodeError, ceea ce nu se poate face în modul idiomatic for iterație. –  > Por flow2k.
NPE

Idiomul Python pentru deschiderea unui fișier și citirea acestuia linie cu linie este:

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

Fișierul va fi închis automat la sfârșitul codului de mai sus (se va închide automat fișierul with se ocupă de acest lucru).

În cele din urmă, este de remarcat faptul că line va păstra linia nouă din urmă. Aceasta poate fi eliminată cu ușurință folosind:

line = line.rstrip()

Comentarii

  • +1, subliniind, de asemenea, către OP că acesta este nu nu este același lucru cu foarte similarul for line in f.readlines(): ..., o soluție sugerată în mod obișnuit. –  > Por jedwards.
A R

Puteți utiliza fragmentul de cod de mai jos pentru a citi linie cu linie, până la sfârșitul fișierului

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

    # Do Something

    line = obj.readline()

Comentarii

  • IMO, acesta este singurul răspuns care reflectă cel mai bine ceea ce s-a cerut. –  > Por W7GVR.
  • Adesea, iterarea peste linii ar denatura structura programului. De exemplu, într-un analizor de limbaj, doriți să citiți liniile și să le procesați în ordine. Nu doriți să restructurați nivelul superior doar pentru a putea citi în buclă liniile și apoi să le trimiteți parserului. –  > Por Jonathan Starr.
user5472996

Deși există sugestii mai sus pentru „a o face în modul python”, dacă se dorește cu adevărat o logică bazată pe EOF, atunci presupun că utilizarea gestionării excepțiilor este modalitatea de a face acest lucru…

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

Exemplu:

$ 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

Sau apăsați Ctrl-Z la un raw_input() prompt (Windows, Ctrl-Z Linux)

Comentarii

  • @TessellatingHeckler că nu este ceea ce documentația spune: „Ridicată atunci când una dintre funcțiile încorporate (input() sau raw_input()) atinge o condiție de sfârșit de fișier (EOF) fără a citi date.” –  > Por Tadhg McDonald-Jensen.
  • @TadhgMcDonald-Jensen Ei bine, așa va fi. Ce ciudat. Afirmație falsă retractată și downvote nedrept eliminat. –  > Por TessellatingHeckler.
Infinity

În plus față de răspunsul minunat al lui @dawg, soluția echivalentă folosind operatorul morsă (Python >= 3.8):

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

Aditeya Pandey

Puteți utiliza următorul fragment de cod. readlines() citește întregul fișier dintr-o dată și îl împarte pe rând.

line = obj.readlines()