Gestione del path
e files#
In questa sezione, andremo ad introdurre un concetto estremamente importante, ovvero quello di path
(assoluto e relativo), e working directory
.
I path sono delle stringhe che indicano l’indirizzo di un file o di una directory all’interno del computer. Quando si specifica un path su Python, è importante distinguere tra il path assoluto e il path relativo.
Path assoluto: Specifica l’intero percorso a partire dalla directory radice. È un percorso completo che include tutte le directory necessarie per raggiungere il file o la directory desiderata. Ad esempio, un file
esempio.txt
, presente sul Desktop, avrà il seguente path:Su macOS/Linux:
/Users/nomeUtente/Desktop/esempio.txt
Su Windows:
C:\Users\nomeUtente\Desktop\esempio.txt
Path relativo: Specifica il percorso rispetto alla directory corrente. Ad esempio, se ci troviamo nel percorso
/Users/nomeUtente/
, un percorso relativo per il fileesempio.txt
sarebbe:./Desktop/esempio.txt
.
A tal proposito, un concetto importante è quello della directory corrente (o working directory). Questo rappresenta la directory in cui il programma Python sta operando, ovvero la radice del progetto Python su cui stiamo lavorando. E’ importante ricordare che tutti i percorsi dei file (per lettura/scrittura), devono essere dati rispetto alla working directory. Altrimenti, si occorre in un’errore.
Warning
Nel seguito, i comandi verranno sempre indicati seguendo la notazione di macOS/Linux. Ricordarsi di modificare la notazione nel caso in cui si lavori con sistemi Windows.
Librerie os
e glob
#
Quando si tratta di gestione del path, due librerie built-in svolgono un ruolo di primaria importanza: la libreria os
e la libreria glob
. Essendo built-in, è possibile semplicemente caricarle in memoria utilizzando il comando import os
e import glob
, rispettivamente.
Vediamo ad esempio come visualizzare e come modificare la working directory, tramite la libreria os
.
import os
# Visualizza la directory di lavoro corrente
print(os.getcwd())
# Modifica la directory di lavoro (se necessario)
os.chdir("/Users/davideevangelista/Desktop")
print(os.getcwd()) # Verifica che la working directory sia cambiata
/Users/davideevangelista/calcolo-numerico/intro
/Users/davideevangelista/Desktop
Oltre a queste, la libreria os
offre varie funzioni per gestire i path. Infatti, alcune funzioni rilevanti di tale libreria sono:
os.path.join(path1, path2, ...)
: Prende in input una serie di stringhe e ritorna in output il path ottenuto concatenando tali stringhe, inserendo automaticamente il separatore corretto in base al sistema operativo.os.listdir(path)
: Dato un path in input, ritorna l’elenco di tutti i files e le directory contenuti in esso, nella forma di una lista.os.path.exists(path)
: Dato un path in input, ritornaTrue
se tale path esiste,False
altrimenti.os.makedirs(path, exists_ok=True)
: Preso in input un path, non fa niente se il path richiesto esiste. Crea invece tutte le cartelle necessarie per costruirlo, se tale path non esiste.
Vediamo alcuni esempi:
# Consideriamo una cartella "data", e supponiamo di avere al suo interno un file
# "esempio.txt"
data_path = "./data"
file_name = "esempio.txt"
# Costruiamo il percorso per il file
path_file = os.path.join(data_path, file_name)
print(path_file)
# Verifica se il path per il file esiste, se no, costuiamolo
if os.path.exists(data_path):
os.makedirs(data_path, exist_ok=True)
# Vediamo se ora esiste
print(os.path.exists(data_path))
./data/esempio.txt
False
La libreria glob
, invece, ha funzionalità simili a quelle di os
, ma è utilizzata principalmente perché permette di selezionare dei files all’interno di un percorso, filtrandoli rispetto ad alcune proprietà.
import glob
# Cerca tutti i file .txt nella directory ./data
data_path = "./data"
file_txt = glob.glob(os.path.join(data_path, "*.txt"))
print(file_txt)
# Oppure in tutte le sue sub-directory
file_python = glob.glob(os.path.join(data_path, "**", "*.txt"), recursive=True)
print(file_python)
[]
[]
Lettura/scrittura di files#
I risultati prodotti da uno script Python, spariscono non appena il programma termina. Per mantenere salvate delle informazioni (o per leggere informazioni precedentemente salvate), è necessario utilizzare dei files.
In Python, questo viene fatto tramite tre diversi standard, dipendentemente dal tipo di informazioni che si vogliono memorizzare/leggere:
tramite un file
.txt
,tramite un file
.json
,tramite la libreria
pickle
.
Vediamo quando ciascuna delle tre possibilità viene utilizzata, e come salvare/leggere quei files.
I files .txt
vengono usati quando si vogliono salvare informazioni di tipo testuale/numerico, in maniera rapida e non strutturata. Per farlo, è necessario aprire il file (tramite la funzione open
), e inserirci i valori desiderati all’interno.
import os
# Creiamo una stringa da salvare
s = "Questa stringa contiene informazioni importanti, da tenere in memoria."
# Definiamo il path
path = os.path.join("logs", "nome_file.txt")
os.makedirs("logs", exist_ok=True)
# Apriamo il file
with open(path, mode="w") as f:
# All'interno del "with" posso lavorare sul file, chiamato "f"
f.write(s)
# Fuori dal "with", il file è stato chiso
Andiamo ad analizzare questo snippet di codice in dettaglio. Come prima cosa, abbiamo aperto i file con la funzione open
, che prende in input due argomenti: il path per il file (in questo caso abbiamo scritto solo il nome del file perché lo vogliamo salvare nella working directory, avremmo dovuto inserire l’intero percorso relativo se avessimo voluto salvarlo all’interno di una directory specifica), e la modalità di apertura. Tra le possibili modalità di apertura, ricordiamo le più comunemente utilizzate:
"w"
: sola scrittura. Il file viene sovrascritto ogni volta."a"
: sola scrittura. Il contenuto viene aggiunto al file, senza sovrascriverlo."r"
: sola lettura.
La funzione open
è stata inserita all’interno del comando with
, che ha lo scopo di tenere aperto il file, solo all’interno del suo corpo. Va variabile associata al file verrà chiusa ed eliminata subito dopo.
Nella stessa linea del comando with
, abbiamo assegnato al file il nome di una variabile (in questo caso f
), che abbiamo poi utilizzato per scrivere al suo interno tramite la funzione f.write()
.
Ovviamente, l’operazione richiesta per leggere il contenuto del file è speculare, utilizzando il metodo .read()
e assegnandolo ad una stringa.
# Andiamo a leggere il contenuto del file appena creato
with open(path, "r") as f:
s = f.read()
print(s)
Questa stringa contiene informazioni importanti, da tenere in memoria.
I file in formato .json
, invece, vengono utilizzati principalmente per salvare informazioni strutturate, come ad esempio dei dizionari, con lo scopo di salvarsi dei dati di configurazione. Per gestire files .json
, è necessario importare la libreria built-in json
.
import json
import os
# Generiamo un dizionario di esempio
config = {
"nome_algoritmo": "MetodoDiscesa",
"parametro1": 10,
"parametro2": 0.01,
}
# Definiamo il path (come prima)
path = os.path.join("logs", "config.json")
# Apriamo un file json in lettura
with open(path, "w") as f:
json.dump(config, f)
Similmente, possiamo leggere i file .json
, convertendoli in dizionari.
import json
import os
# Definiamo il path (come prima)
path = os.path.join("logs", "config.json")
# Apriamo un file json in lettura
with open(path, "r") as f:
config = json.load(f)
print(config)
{'nome_algoritmo': 'MetodoDiscesa', 'parametro1': 10, 'parametro2': 0.01}
Parliamo, infine, del formato .pickle
. Questo è sicuramente il formato più utilizzato per memorizzare informazioni di output da Python. Il suo nome deriva dalla libreria built-in pickle
, che fornisce le funzionalità necessarie al suo utilizzo.
Il vantaggio di pickle è che permette di leggere/scrivere su file ogni oggetto Python, che verrà memorizzato nella forma in cui è, e ricaricato nello stesso modo.
La sintassi è praticamente la stessa di prima:
import pickle
# Definiamo un qualunque oggetto Python (ad esempio, una lista)
a = [1, 3, ("c", "i", "a", "o")]
# Definiamo il path
path = os.path.join("logs", "file.pickle")
# Salviamo con Pickle
with open(path, "wb") as f:
pickle.dump(a, f)
# Leggiamo il file pickle
with open(path, "rb") as f:
b = pickle.load(f)
print(b)
[1, 3, ('c', 'i', 'a', 'o')]