Corso Python / Percorsi di file e cartelle con pathlib e Path

La classe Path di pathlib rappresenta percorsi di file e cartelle e ne combina le parti secondo le regole del sistema operativo. Un percorso relativo parte dalla cartella di lavoro corrente, che può essere diversa dalla cartella in cui hai salvato lo script.

Combinare i percorsi senza separatori manuali

Con Path("data") / "expenses.csv" componi un percorso senza inserire a mano barre inverse di Windows o separatori specifici per ogni piattaforma. L’operatore / crea un altro oggetto percorso: non crea ancora una cartella né un file sul disco.

Path.cwd() restituisce la cartella di lavoro. In uno script, Path(__file__).resolve().parent individua invece la cartella del file sorgente; in un ambiente interattivo __file__ può non esistere. Scegli quale base serve all’applicazione: dati forniti dall’utente nella cartella corrente e risorse accanto al programma non hanno necessariamente lo stesso riferimento.

Un oggetto Path usa le regole della piattaforma su cui gira Python. Per analizzare soltanto la sintassi di percorsi di un’altra piattaforma esistono PureWindowsPath e PurePosixPath, che non eseguono operazioni sul file system. La documentazione ufficiale di pathlib distingue questi casi e descrive gli attributi del percorso.

Creare e controllare un file di esercizio

Prepara una cartella nuova riservata alla prova. Il programma crea lab-data/expenses.csv sotto la cartella di lavoro e ne sostituisce il contenuto a ogni esecuzione: non usarlo su dati che vuoi conservare. Non richiede librerie esterne.

Salva il codice completo come paths.py, in UTF-8. Dal terminale aperto nella cartella dell’esercizio, con l’interprete del progetto selezionato, esegui python paths.py. Fuori dall’ambiente virtuale su macOS o Ubuntu usa python3 se quello è il comando dell’interprete scelto.

from pathlib import Path

base = Path("lab-data")
base.mkdir(exist_ok=True)
path = base / "expenses.csv"
path.write_text("name,amount\nlunch,8000\n", encoding="utf-8")
print(path.name, path.suffix, path.stem)
print(path.is_file(), base.is_dir())
print(sorted(p.name for p in base.glob("*.csv")))

In una cartella inizialmente vuota il risultato è:

expenses.csv .csv expenses
True True
['expenses.csv']

name contiene il nome completo dell’ultimo componente, suffix l’ultima estensione e stem il nome senza quell’estensione. Per esempio, in un nome come archive.tar.gz, stem conserva archive.tar: non rimuove automaticamente tutte le estensioni.

mkdir(exist_ok=True) tollera una cartella già esistente; non rende accettabile un file ordinario al suo posto. write_text scrive il testo, con codifica esplicita, e chiude il file. Apri il CSV generato: deve contenere l’intestazione name,amount e la riga lunch,8000. La virgola nel testo separa i due campi; qui non stiamo ancora elaborando il CSV con un lettore strutturato.

Interpretare ricerche e controlli di esistenza

glob("*.csv") cerca i componenti corrispondenti nella cartella indicata; rglob("*.csv") include anche le sottocartelle. Una cartella può avere un nome che termina in .csv: quando vuoi solo file, filtra i risultati con is_file(). Non affidarti all’ordine del file system; sorted rende stabile l’elenco visualizzato.

La terza riga dell’output presuppone che expenses.csv sia l’unica corrispondenza nella cartella lab-data. Se aggiungi altri CSV, l’elenco cambia anche se il programma è corretto. La chiamata glob dell’esempio non scende nelle sottocartelle.

Un controllo con exists() descrive un momento, non riserva il percorso. Tra la verifica e la lettura un altro processo può spostare o eliminare il file. Anche permessi, destinazioni occupate ed errori del disco devono essere gestiti durante l’operazione effettiva; non basta mettere exists prima di ogni scrittura.

Prima di un’operazione importante, rendi chiara la destinazione con path.resolve() e definisci una politica di sovrascrittura. Risolvere il percorso aiuta a capire dove stai lavorando, ma non garantisce da solo che la scrittura sia autorizzata o che il percorso non cambi successivamente.

Confrontare cartella di lavoro e cartella dello script

Puoi eseguire lo stesso file da una cartella diversa indicando il suo percorso completo nel comando Python. Poiché base è relativa, verrà creata un’altra lab-data nella nuova cartella di lavoro: lo script non comincia automaticamente a usare la cartella in cui è salvato. Anche l’avvio di un package tramite -m non trasforma ogni percorso relativo in un percorso accanto al sorgente.

  1. Esegui la versione originale nella cartella di prova e verifica sia le tre righe stampate sia il contenuto del CSV.
  2. In una copia separata cambia soltanto il nome expenses.csv in report.csv. Confronta name, stem e suffix; il testo contenuto nel file resta invariato.
  3. Esegui lo script originale da un’altra cartella di prova usando il suo percorso completo. Individua la nuova lab-data sotto quella cartella di lavoro.
  4. Ripristina il nome originale e la cartella di lavoro iniziale. Prima di eliminare i file dell’esercizio, controlla i percorsi assoluti e limita la pulizia ai file di prova appena creati.

Quando la destinazione deve essere accanto allo script, costruiscila esplicitamente a partire da Path(__file__).resolve().parent. Quando invece il percorso arriva dall’esterno, considera componenti come .., percorsi assoluti e collegamenti simbolici. Un componente assoluto può sostituire la base che pensavi di usare; il semplice confronto del prefisso testuale non distingue, per esempio, una cartella consentita da un’altra con lo stesso inizio del nome.

Per verificare l’appartenenza a una base puoi confrontare percorsi risolti con operazioni sui percorsi, ma un’applicazione esposta a modifiche concorrenti del file system richiede controlli ulteriori. Non presentare un confronto di stringhe come barriera di sicurezza e non applicare spostamenti o cancellazioni a percorsi non verificati.