La risposta breve
Per verificare se un file esiste, usa os.path.isfile() della libreria standard. Restituisce True quando il percorso indica un file regolare esistente e False altrimenti. Non solleva mai un errore per un percorso mancante.
I percorsi sono relativi alla cartella in cui gira il programma (la directory di lavoro corrente), a meno che tu non passi un percorso assoluto come /home/ada/notes.txt o C:\Users\Ada\notes.txt.
Il resto della pagina mostra gli altri modi per porre la domanda, in cosa differiscono e il caso in cui non dovresti porla affatto.
os.path.exists vs isfile vs isdir
Il modulo os.path ha tre controlli collegati, che rispondono a domande leggermente diverse:
| Funzione | Restituisce True quando il percorso è |
|---|---|
os.path.exists(p) | qualsiasi cosa esista: un file, una cartella o un link simbolico funzionante |
os.path.isfile(p) | un file regolare esistente |
os.path.isdir(p) | una cartella esistente |
La differenza si vede appena c'è di mezzo una cartella:
Output:
reports True False True
reports/summary.txt True True False
reports/old.txt False False False
os.path.exists("reports") è True anche se reports è una cartella. Se il tuo codice sta per leggere il percorso come file, exists è il controllo sbagliato: una cartella lo supererebbe, e poi open("reports") fallirebbe (con IsADirectoryError su Linux e macOS, PermissionError su Windows). Scegli isfile quando intendi un file e isdir quando intendi una cartella.
Altri due dettagli su queste tre funzioni di os.path:
- I link simbolici vengono seguiti. Un link che punta a un file reale conta come file; un link rotto (la destinazione non c'è più) restituisce
Falseda tutte e tre. - Se Python non ha il permesso di guardare dentro una cartella, il controllo restituisce
Falseinvece di sollevarePermissionError.Falsesignifica "non trovato o non raggiungibile", non strettamente "non esiste".
Verificare con pathlib
pathlib è l'API a oggetti per i percorsi della libreria standard, e la usa la maggior parte del codice nuovo. Un oggetto Path ha gli stessi tre controlli come metodi:
Path.exists(), Path.is_file() e Path.is_dir() si comportano come os.path.exists, isfile e isdir. L'operatore / unisce le parti del percorso con il separatore giusto per il sistema operativo, quindi folder / "summary.txt" funziona allo stesso modo su Windows, macOS e Linux. Vedi la gestione dei file per leggere e scrivere tramite oggetti Path.
Quale usare? Se il resto del tuo codice passa già oggetti Path, resta su pathlib. Se lavori con stringhe semplici e funzioni di os, os.path.isfile è altrettanto corretto. Danno le stesse risposte.
Perché verificare prima può essere la mossa sbagliata
Il motivo più comune per verificare se un file esiste è aprirlo subito dopo:
import os
if os.path.isfile("config.txt"):
with open("config.txt") as f: # il file potrebbe non esserci più
settings = f.read()
else:
settings = ""
C'è un buco. Tra la chiamata a isfile() e quella a open(), un altro programma, un altro thread o l'utente possono cancellare o rinominare il file. Il controllo ha detto True, l'apertura fallisce comunque e il tuo programma si blocca con FileNotFoundError. Questo buco si chiama race condition, o "time of check to time of use". È raro sul tuo portatile e molto meno raro su un server affollato dove più processi condividono una cartella.
La soluzione è saltare il controllo separato e lasciare che sia open() a fare il controllo. Python solleva FileNotFoundError quando il file manca, e tu lo gestisci in except:
Output:
theme=dark
(no settings file, using defaults)
Ora c'è un'operazione sola invece di due, quindi non c'è nessuna corsa possibile. Nella comunità Python questo stile ha un nome: EAFP, "easier to ask forgiveness than permission" (è più facile chiedere perdono che permesso). Lo stile opposto, controllare prima, è LBYL, "look before you leap" (guarda prima di saltare). Per i file Python preferisce EAFP, perché solo il sistema operativo conosce la risposta nel momento in cui apri il file.
FileNotFoundError non è l'unica cosa che può andare storta. Un percorso che è una cartella solleva IsADirectoryError (PermissionError su Windows), e un file che non puoi leggere solleva PermissionError. Sono tutte e tre sottoclassi di OSError, quindi except OSError: cattura in un colpo solo ogni caso di "non sono riuscito ad aprirlo". La pagina sulle eccezioni spiega come scegliere tra catturare un errore specifico e catturarne un'intera famiglia.
Quando un semplice controllo va bene
Verificare prima non è sbagliato in ogni caso. È lo strumento giusto quando ti serve solo la risposta e non stai per agire sul file alla riga successiva:
- scegliere quale messaggio mostrare ("Found 3 saved games")
- validare un percorso digitato dall'utente prima di avviare un lavoro lungo
- saltare un lavoro già fatto, dove una risposta non aggiornata costa al massimo una ripetizione
La regola pratica: se stai per aprire, leggere, scrivere o cancellare il file, fallo dentro try. Se vuoi solo saperlo, isfile() o Path.is_file() vanno benissimo.
Creare un file solo se non esiste
Capita anche la domanda opposta: "scrivi questo file, ma non sovrascriverne mai uno esistente". La versione più ovvia ha la stessa race condition di prima:
if not os.path.exists("report.txt"):
with open("report.txt", "w") as f: # un altro processo può crearlo prima
f.write("new report\n")
La modalità "x" (creazione esclusiva) fa entrambi i passaggi in uno. Crea il file, oppure solleva FileExistsError se il nome è già preso:
Output:
attempt 1: created report.txt
attempt 2: report.txt already exists, left it alone
Per le cartelle, os.makedirs(path, exist_ok=True) e Path(path).mkdir(parents=True, exist_ok=True) creano la cartella e tutte quelle superiori mancanti, e non fanno nulla se esiste già. Non serve chiamare prima isdir().
Errori comuni
- Usare
exists()quando intendi un file. Una cartella con lo stesso nome supera il controllo. Usaisfile()oPath.is_file(). - Dimenticare da dove partono i percorsi relativi.
"data.txt"viene cercato nella directory di lavoro corrente, cioè dove hai avviato il programma, non per forza la cartella che contiene lo script. Per trovare un file accanto allo script, costruisci il percorso partendo daPath(__file__).parent. - Verificare e poi aprire. Il file può cambiare nel frattempo. Apri dentro
trye gestisciFileNotFoundError. - Catturare qualsiasi eccezione.
except Exception:attorno aopen()nasconde anche errori di battitura e bug nel codice che legge il file. CatturaFileNotFoundErroroOSError.
Domande frequenti
Come verifico se un file esiste in Python?
Importa os e chiama os.path.isfile("data.txt"), che restituisce True solo per un file regolare esistente. Con pathlib è Path("data.txt").is_file(). Usa os.path.exists() o Path.exists() quando anche una cartella con quel nome deve contare.
Qual è la differenza tra os.path.exists e os.path.isfile?
os.path.exists(p) è True per qualsiasi cosa si trovi in quel percorso: un file, una cartella o un link simbolico che punta a qualcosa di reale. os.path.isfile(p) è True solo per un file regolare, quindi restituisce False per una cartella. os.path.isdir(p) è l'equivalente per le cartelle.
Devo verificare se un file esiste prima di aprirlo?
Di solito no. Il file può essere cancellato o creato tra il controllo e la chiamata a open(), quindi il controllo non garantisce nulla. Apri il file direttamente dentro try e gestisci FileNotFoundError in except. Un controllo separato ha senso quando ti serve solo la risposta, per esempio per decidere quale messaggio mostrare.
Come creo un file solo se non esiste?
Aprilo in modalità "x": open("report.txt", "x"). Python crea il file, oppure solleva FileExistsError se lì c'è già qualcosa. Il controllo e la creazione avvengono in un solo passaggio, quindi nessun altro programma può inserirsi in mezzo.