Alessio Forti

Creare e leggere file con Python

In certe situazioni può capitare di dover ricorrere all’aiuto di un file esterno per memorizzare dei dati, siano questi dati permanenti che verranno utilizzati in un’esecuzione successiva del programma, sia che si tratti di file temporanei.
Vediamo come sia estremamente semplice poter scrivere e leggere un file con Python.

Per capire come funziona la creazione e la lettura di un file creeremo passo passo un programma molto semplice che eseguirà le seguenti azioni:

  1. Creare un file .txt,
  2. scrivere nel file tutti i numeri pari minori di 100, uno per riga,
  3. leggere il file e calcolare la somma di tutti i numeri contenuti nel file.

Bene, ora vi starete chiedendo perché per calcolare la somma di tutti i numeri pari minori di 100 dobbiamo scriverli e poi leggerli da un file. In breve, non ne ho la più pallida idea. Nonostante questo, l’importante è capire come utilizzare le funzioni predefinite di Python a nostro favore.

Creiamo il file

Il seguente script crea un file di nome pari.txt e su ogni riga scrive un numero purché sia pari e minore di 100:

documento = open("pari.txt", "w")

for i in range(1,100):
	if i%2==0:
		riga = "%i\n" % (i)
		documento.write(riga)

documento.close()

La creazione fisica del file avviene quando l’interprete incontra la prima riga ed in questo caso avviene nella stessa cartella dello script.
open() è una funzione predefinita in Python e quindi è sempre disponibile e accetta tre argomenti: il nome del file da aprire, il modo, e il buffer (di cui non parleremo). Per quanto riguarda il nome del file c’è poco da dire, al contrario per quanto riguarda il modo c’è da sapere che può essere di diversi tipi, quelli più usati sono rw e a. Come forse avrete capito r e w stanno per “read” e “write” e a per “append”; in sostanza questi flag specificano quello che si può fare con il file appena aperto. Inoltre esistono anche le versioni dei flag con il suffisso “+” (r+w+a+), per esempio r+ apre il file in lettura e scrittura.
Una cosa importante da capire è che non stiamo usando una funzione chiamata per esempio “create()”, ma stiamo usando una funzione chiamata open(). La cruda realtà è che non stiamo creando esplicitamente un file ma stiamo cercando di aprirlo in modalità scrittura, da questo ne consegue che se il file esiste già il file verrà sovrascritto (e quindi perderemo tutti i dati che conteneva: attenzione!), altrimenti ne verrà creato uno nuovo. Carino, giusto?
Nelle quattro righe che seguono controlliamo se un numero è pari, se lo è creiamo una stringa formattata (riga) che contiene il numero e il carattere di ritorno a capo("n"). Chiamiamo il metodo.write() sul nostro file passandogli come argomento la nostra stringa formattata (bisogna trasformare tutto in stringa prima di poter scrivere nel file), come potete immaginare .write() scrive direttamente nel file. Ripetere il tutto fino a 100. Infine chiamiamo .close() sul nostro file in modo da non renderlo più accessibile e anche per liberare quel poco di memoria che abbiamo occupato.

Leggiamo il file

Ora che abbiamo creato il file è venuto il tempo di calcolare la somma di tutti i numeri contenuti al suo interno. Per fare questo il file va letto e “lavorato”, esistono diversi modi per farlo e noi ne vedremo un paio.

Modo numero 1:

documento = open('pari.txt', 'r')
p = pari.readlines()

for i in range(0, len(p)):
    p[i] = int(p[i].strip('n')
print sum(p)
pari.close()

Dunque, apriamo il nostro file in modalità sola lettura e lo assegnamo a pari. Poi creiamo la variabile p che conterrà il risultato di pari.readlines(). Questo metodo ritorna una lista in cui ogni posizione è una riga del file ritornato come stringa.
p risulterà essere così:

['2n', '4n', '6n', ... , '94n', '96n', '98n']

vediamo che come ci si aspettava ogni posizione contiene una riga del file, la cosa che forse ci aspettavamo di meno è il segno di ritorno a capo alla fine di ogni valore. Che cosa ti aspettavi? Lo abbiamo creato noi in questo modo! Per rimediare a questo problema usiamo un ciclo for in modo da fare due lavori in uno: rimuovere n e trasformare il nostro valore in un intero usando int(). Con.strip() (che è un metodo applicabile alle stringhe) possiamo rimuovere da una stringa i caratteri che gli passiamo come argomento.
La nuova lista sarà una splendida lista di interi:

[2, 4, 6, 8, ... , 92, 94, 96, 98]

Non ci resta che sommare il tutto con sum() e chiudere il file.

Modo numero 2:

pari = open('pari.txt', 'r').read()
p = pari.split('n')
p.pop(len(p)-1)

for i in range(0,len(p)):
    p[i] = int(p[i])

print sum(p)

Al solito apriamo il nostro file ma questa volta aggiungiamo ad open() il metodo .read(). Qest’ultimo ritorna una stringa contenete l’intero file compresi i ritorni a capo delle righe e, da notare, anche l’ultimo ritorno a capo presente nell’ultima riga (insomma una riga vuota, di nessuna utilità ai nostri scopi), ma di questo ce ne occuperemo tra poco. Ora, il problema è come riuscire ad estrarre i valori da questa stringa piuttosto lunga. Ci viene in soccorso il metodo .split() il quale, applicato ad una stringa con dei caratteri ricorrenti, ritorna una lista contenente i caratteri compresi tra quelli ricorrenti che gli sono stati passati come argomento. Forse un bell’esempio può chiarire meglio:

'1 2 3 4'.split(' ')
>>> ['1', '2', '3', '4']
'1%?2%?3%?4'.split('%?')
>>> ['1', '2', '3', '4']

Bene, così facendo abbiamo una lista di stringhe senza il carattere di ritorno a capo. Ora dobbiamo occuparci dell’ultima posizione della lista che è l’ultima riga (vuota) del file. Possiamo semplicemente rimuoverla tramite .pop() che, udite udite, rimuove gli elementi da una lista: gli passiamo l’ultima posizione della lista (len(p)-1). Ora come prima occorre convertire gli elementi della lista in intperché al momento sono stringhe. Un bel ciclo for fa al caso nostro. Dopodiché basta sommare gli elementi ed il gioco è fatto.

Conclusione

Esistono diversi modi con cui si può leggere un file, ognuno varia in base allo scopo che dobbiamo raggiungere. In questo caso, sommare i numeri contenuti in un file era un pretesto per vedere come manipolare dei dati ricevuti in ingresso e come esistano diverse forme per farlo. Per inciso, si sarebbe potuto usare il metodo .readline() (senza la “s”) che legge una riga per volta ed iterarlo per fino alla fine del file.
Quello che conta è riuscire a creare un file, leggere il suo contenuto e rendere utilizzabili i dati contenuti al suo interno.

È possibile scaricare il file completo qui.