4.1 Chiusura del file e gestione degli errori
A volte, quando si legge un file, si verificano errori o eccezioni e il file rimane
non chiuso. Questo può potenzialmente portare a una perdita di memoria o
perdita di file handler
. Pertanto, il lavoro con il file deve essere racchiuso in
un blocco try-except
.
Supponiamo che tu abbia il codice:
file = open('example.txt', 'a') # Apriamo il file
file.write("This is a new line added to the file.")
file.close() # Chiudiamo il file
Deve essere incapsulato in un blocco try-except
:
try:
file = open('example.txt', 'a') # Apriamo il file
file.write("This is a new line added to the file.")
file.close() # Chiudiamo il file
except FileNotFoundError:
print("File not found")
file.close() # Chiudiamo il file
Per evitare di scrivere due volte il metodo close()
, puoi metterlo in un blocco
finally
:
try:
file = open('example.txt', 'a') # Apriamo il file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Chiudiamo il file
Questo codice sembra bello, ma... non funziona, perché la variabile file
è definita solo nel blocco try
e non è accessibile dai blocchi except
e finally
.
Quindi dobbiamo definire la variabile a un livello superiore:
file = None
try:
file = open('example.txt', 'a') # Apriamo il file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Chiudiamo il file
Questa soluzione è migliore, ma ha anche dei difetti. Ad esempio, se il file
non viene mai aperto, la variabile file
rimarrà None
. E allora
tentare di chiudere il file genererà un errore — ci sarà un tentativo di chiamare
il metodo close()
su un oggetto inesistente.
Quindi dobbiamo aggiungere un controllo prima di chiamare il metodo close()
:
file = None
try:
file = open('example.txt', 'a') # Apriamo il file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
if file:
file.close() # Chiudiamo il file
Se sei sorpreso che 3 righe di codice si siano trasformate in 9, non sei solo. Fortunatamente, c'è già una soluzione pronta a questo problema, di cui parleremo di seguito.
4.2 Operatore with
L'operatore with
in Python fornisce un modo conveniente di gestire
le risorse, come i file, assicurando che vengano chiuse automaticamente
dopo il completamento del blocco with
. Questo semplifica il codice e previene le perdite
di risorse, come i file non chiusi.
Sintassi generale dell'operatore with
:
with espressione as variabile:
lavoro con la variabile
L'operatore with
viene utilizzato per
incapsulare l'esecuzione di un blocco di codice con un gestore di contesto. Alla
utilizzo dell'operatore with
, Python chiama automaticamente
i metodi __enter__()
e
__exit__()
dell'oggetto gestore di contesto, il che semplifica
la gestione delle risorse.
Esempio di utilizzo di with
per lavorare con i file:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
In questo esempio, il file example.txt
viene aperto in modalità scrittura, e il nome
del file viene associato alla variabile file
. Il blocco di codice
all'interno del with
chiude automaticamente il file dopo aver completato tutte le operazioni di scrittura.
4.3 Chiusura automatica del file
Uno dei principali vantaggi dell'utilizzo
dell'operatore with
è la chiusura automatica
del file dopo il completamento del blocco di codice. Ciò avviene
anche in caso di eccezione, rendendo
il codice più sicuro e affidabile.
Esempio di chiusura automatica del file:
try:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
# Eccezione per verificare che il file si chiuda comunque
raise Exception("Something went wrong")
except Exception as e:
print(f"Caught an exception: {e}")
# Qui il file è già chiuso
Usa sempre l'operatore with
quando
lavori con i file. È semplice e ti aiuta a evitare una miriade di errori.
4.4 Come funziona l'operatore with
Alla base del funzionamento dell'operatore with
vi sono i metodi __enter__()
e
__exit__()
, che devono essere implementati nella classe utilizzata
come gestore di contesto.
Affinché un oggetto possa essere utilizzato con
l'operatore with
, deve implementare i metodi __enter__()
e
__exit__()
. Questi metodi definiscono il comportamento all'ingresso e
all'uscita del contesto.
Metodo __enter__()
Il metodo __enter__()
è chiamato all'entrata nel blocco with
.
Esegue l'inizializzazione della risorsa e restituisce un oggetto che
sarà assegnato alla variabile specificata dopo as
.
Metodo __exit__()
Il metodo __exit__()
è chiamato alla fine del blocco with
. Esegue
operazioni di pulizia come il rilascio delle risorse o la chiusura
dei file. Il metodo accetta tre argomenti: exc_type
, exc_val
e exc_tb
,
che contengono informazioni sull'eccezione, se si verifica.
-
exc_type
: il tipo di eccezione (ad esempio,ZeroDivisionError
). -
exc_val
: il valore dell'eccezione (ad esempio, il messaggio di errore). exc_tb
: la traccia dello stack dell'eccezione.
Se il metodo __exit__()
restituisce True
,
l'eccezione sarà soppressa. Se restituisce
False
, l'eccezione sarà nuovamente sollevata.
Esempio:
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
print(f"An exception occurred: {exc_type}, {exc_val}")
return False # L'eccezione non viene soppressa
with MyContextManager() as manager:
print("Inside the with block")
GO TO FULL VERSION