Scurtă teorie și exemple
Last updated
Last updated
De cele mai multe ori, nu este comod să lucrăm cu date introduse de la tastatură. Mai mult decît atît, sîntem și limitați, pentru că dacă vrem să realizăm un test pe sute sau mii de numere ori linii de text, va fi foarte greu să le introducem manual, de la tastatură. De aceea, în majoritatea situațiilor, se preferă lucrul cu fișiere text. Acestea pot fi folosite atît ca date de intrare, cît și ca date de ieșire. Cu alte cuvinte, vom putea citi din fișier datele pe care le prelucrăm și vom putea scrie în fișier rezultatul calculelor.
Vom prezenta pe scurt în acest laborator lucrul cu fișiere text, atît pentru date de intrare, cît și pentru date de ieșire. În mare, putem lucra cu astfel de fișiere detaliate în codul sursă, sau le putem folosi drept argumente atunci cînd rulăm programul. Vom vedea avantajele și dezavantajele fiecăreia dintre cele două metode.
Observație: Exemplele de mai jos se vor adresa problemelor de lucru cu fișiere text simple, aflate în directorul curent sau cu o cale cunoscută. Pentru lucrul cu fișiere la nivel de sistem, se poate folosi modulul .
Ca în majoritatea limbajelor de programare, lucrul cu fișiere se bazează pe atribuirea lor la variabile din program, precum și pe folosirea unor funcții specifice de citire și scriere.
Una dintre cele mai simple metode în Python este aceasta:
În exemplul de mai sus, fișierul fisier_intrare.txt
, care se află în același director cu sursa programului este deschis folosind funcția open
. El se deschide pentru citire, ceea ce se vede din argumentul "r"
(pentru read
). Conținutul fișierului se accesează atunci cînd folosim metoda read()
. Fără aceasta, variabila file
doar face legătura (este un fel de pointer) cu fișierul respectiv.
Funcția read()
citește întreg conținutul fișierului. Dar putem să precizăm cîte caractere să se citească din fișier, dînd un argument. Astfel, un apel precum
păstrează primele 3 caractere din fișier în variabila caractere
, de tip string
.
Scrierea în fișiere este la fel de intuitivă:
Deschidem de data aceasta un fișier pentru scriere (dînd argumentul "w"
la funcția open
) și scriem în fișier cu metoda write
.
Pentru evitarea erorilor, se recomandă ca fișierele deschise pentru scriere sau citire să se închidă cînd nu se mai folosesc, cu metoda close()
. Astfel, dacă linia respectivă este tot ce am vrea să scriem în fișier, de exemplu, completăm codul:
Modul write
șterge fișierul și scrie doar conținutul pe care îl precizăm (face overwrite). Dacă fișierul pe care îl deschidem pentru scriere mai conține deja text, putem folosi modul append
, care adaugă ceea ce indicăm la conținutul deja existent. Astfel, am avea:
Dacă vrem doar să creăm un fișier (eventual, pentru utilizare ulterioară), folosim modul "x"
pentru open
. Astfel, se creează fișierul în directorul specificat (directorul curent este implicit) sau se returnează o eroare dacă fișierul deja există:
În cazul în care fișierul există, programul termină cu eroarea FileExistsError
.
O metodă specială și ceva mai sigură de lucru cu fișiere este cea care folosește instrucțiunea with
, ca în exemplul de mai jos:
Lucrul cu with
are avantajul că închide automat fișierul cînd se iese din bucla respectivă. În plus, din punct de vedere tehnic, leagă variabila f
de fișier doar în bucla respectivă (scope-ul variabilei este doar în bucla respectivă).
Acum, nu mereu avem nevoie să folosim tot conținutul unui fișier ca date de intrare. Sau poate vrem să-l procesăm linie cu linie ori propoziție cu propoziție. Pentru aceasta, în loc de metoda read()
, avem alternative.
Metoda readlines()
citește liniile din fișier și le salvează într-o listă, fiecare element al listei fiind o linie din fișier. Dacă vrem să obținem apoi cuvintele din fiecare linie, de exemplu, folosim metoda split()
. Aceasta folosește drept separator implicit spațiul, dar putem preciza separatorul, dacă vrem, de exemplu, să separăm după propoziții. Iată un exemplu simplu:
ATENȚIE: Atunci cînd citim dintr-un fișier, cursorul rămîne la finalul fișierului. Astfel, două instrucțiuni consecutive de citire nu vor produce rezultatul așteptat. Prima instrucțiune citește, lasă cursorul la final (sau unde s-a terminat citirea), iar a doua instrucțiune continuă citirea din punctul respectiv. Pentru reluarea citirii se foloseste metoda seek
. Aceasta acceptă două argumente:
primul argument este numărul de poziții unde să se plaseze cursorul;
al doilea argument precizează referința, adică față de ce poziție se calculează primul argument. Acesta poate fi:
0
pentru începutul fișierului. Este valoarea folosită implicit și poate lipsi;
1
înseamnă față de poziția curentă;
2
înseamnă față de finalul fișierului.
Exemple:
ATENȚIE: Limbajul nu ne permite să folosim un offset negativ față de poziția curentă. Astfel, funcția f.seek(-2, 1)
va returna o eroare. Acest lucru se rezolvă folosind fișierul deschis cu modul binar, adică "rb"
. Dar atunci, fiecare rezultat va fi afișat sub forma b'1'
, ceea ce se rezolvă codificînd la loc cu formatul utf-8
.
Dacă nu mai știm unde ne aflăm în fișier, putem folosi metoda tell()
, care afișează poziția din fișier unde ne aflăm.
Putem să precizăm fișierul cu care lucrăm la rulare, cu ajutorul argumentelor. Situația funcționează similar cu variabilele de tip argc
și argv
din C. Avem nevoie de modulul sys
, care conține, printre altele, și lista argv
. Astfel, sys.argv[0]
este numele programului, iar apoi urmează argumentele date de la tastatură.
În varianta simplă, vom implementa un program care să precizeze la rulare fișerul de intrare și cel de ieșire, astfel încît să-l putem rula cu
Pentru aceasta, nu avem decît să începem programul cu:
Putem fi și mai preciși, ca să facem rularea mai sugestivă. Astfel, putem folosi flag-uri, care să precizeze care dintre argumente este fișierul de intrare și care este cel de ieșire. Urmărim, deci, o rulare de forma:
Sau, în varianta lungă:
Pentru aceasta, avem nevoie de modulul getopt
, care ne permite să preluăm argumentele într-o listă. Acest modul conține o funcție cu același nume (deci se apelează cu getopt.getopt()
) și este mai flexibil decît preluarea pur și simplu în lista sys.argv
, deoarece permite utilizarea flag-urilor scurte și a celor lungi într-o manieră flexibilă.
Pentru a realiza cele de mai sus, atît în varianta scurtă, cît și în cea lungă, avem o sursă de forma:
În exemplul de mai sus, funcția getopt.getopt()
primește următoarele argumente:
lista din care să ia opțiunile (în cazul nostru, argv
, care este sys.argv[1]
);
o listă de opțiuni scurte, apelate cu liniuță, dar fără liniuță. Lista se separă prin două puncte dacă sînt opțiuni care cer argument. Astfel, i:o:
înseamnă că flag-urile -i
și -o
cer neapărat argument. Dacă aveam și un flag care nu cere argument, el se preciza fără două puncte, de exemplu în forma i:o:x
, deci un astfel de program putea fi rulat cu
o listă de opțiuni lungi, apelate cu două liniuțe, dar fără liniuțe și precizate într-o listă cu sintaxa din exemplu (obligatoriu cu egal). Exemplul de mai sus înseamnă că programul acceptă argumente lungi de forma --infile
și --outfile
.
Funcția getopt.getopt()
returnează perechi de forma (argument, valoare)
, pe care le prelucrăm ulterior.
config.json
O variantă modernă pentru a transmite orice fel de argumente către un program este să folosim fișiere de configurare. Formatul JSON este foarte popular și Python include un parser destul de ușor de utilizat.
Astfel, soluția propusă este să creăm un fișier de configurare JSON care să conțină orice argumente dorim, pe care apoi le preluăm în programul Python. Avem nevoie de modulele argparse
și json
, dar într-o variantă minimală.
Atunci, nu avem decît să rulăm programul cu o comandă precum:
și va prelua automat configurația din fișierul config.json
.
De exemplu, în config.json
putem avea:
Iar apoi în Python vom scrie:
În exemplul de mai sus, args
este un parser, care are atîtea opțiuni cîte precizăm prin add_argument
. Astfel, am adăugat doar opțiunea -c
sau --config
, deci de aceea putem apela args.config
.
Cîteva exemple, precum și utilizarea lor găsiți în exercițiile rezolvate de mai jos.
Puteți studia exemplul
Puteți studia exemplul .
Mai multe detalii, de exemplu, .
Documentația oficială este .
Documentația oficială este .
Acestea se găsesc în modulul math
, a cărui documentație este .
;
;
;
.