Skip to content

“try … except … else … finally …” in Python

Python

In Python, try ed eccetto sono usati per gestire le eccezioni (= errori rilevati durante l’esecuzione). Con try e salvo, anche se si verifica un’eccezione, il processo continua senza terminare. Puoi usare else e infine per impostare il processo finale.

In questo articolo vengono descritti i seguenti contenuti.

  • Gestione delle eccezioni di base in Python:try ... except ...
  • Cattura più eccezioni
    • eseguire operazioni diverse a più eccezioni
    • applicare la stessa operazione a più eccezioni
  • Cattura tutte le eccezioni
    • Carattere jolly tranne (escluso nudo)
    • Classe base:Exception
  • Esegui l’azione se nessuna eccezione:try ... except ... else ...
  • Azione di pulizia:try ... except ... finally ...
  • Ignora le eccezioni:pass
  • Esempio pratico: Lettura di file immagine

Gestione delle eccezioni di base in Python:try ... except ...

Ad esempio, quando si tenta di dividere per zero, viene generato ZeroDivisionError e il processo termina.

# print(1 / 0)
# ZeroDivisionError: division by zero

Per questa cattura eccezione, scrivi come segue:

try:
    print(1 / 0)
except ZeroDivisionError:
    print('Error')
# Error

Impostando eccetto come :, l’oggetto eccezione viene memorizzato nella variabile. È possibile specificare qualsiasi nome vengono utilizzati per la variabile, ma spesso utilizzati nomi come ed err.

L’oggetto eccezione contiene messaggi di errore che vengono emessi quando si verifica un’eccezione ed è possibile verificare i dettagli dell’errore emettendolo.

try:
    print(1 / 0)
except ZeroDivisionError as e:
    print(e)
    print(type(e))
# division by zero
# <class 'ZeroDivisionError'>

In Python2, come scrivere come eccetto, :.

Puoi anche specificare una classe base. Ad esempio, ArithmeticError è la classe base per ZeroDivisionError. La variabile memorizza l’oggetto eccezione della classe derivata che si è verificato.

print(issubclass(ZeroDivisionError, ArithmeticError))
# True

try:
    print(1 / 0)
except ArithmeticError as e:
    print(e)
    print(type(e))
# division by zero
# <class 'ZeroDivisionError'>

Consulta la documentazione ufficiale per le eccezioni integrate in Python.

Quando si verifica un’eccezione nella clausola try, il processo successivo nella clausola try viene ignorato.

Come mostrato nell’esempio seguente, se si verifica un’eccezione nel mezzo del ciclo per, il ciclo per termina in quel punto e il processo nella clausola esclude viene eseguito.

try:
    for i in [-2, -1, 0, 1, 2]:
        print(1 / i)
except ZeroDivisionError as e:
    print(e)
# -0.5
# -1.0
# division by zero

È possibile specificare il processo da eseguire dopo la clausola exclude nelle clausole else efinale più avanti.

Cattura più eccezioni

Definire la seguente funzione che intercetta ZeroDivisionError.

def divide(a, b):
    try:
        print(a / b)
    except ZeroDivisionError as e:
        print('catch ZeroDivisionError:', e)

Con questa funzione è possibile rilevare ZeroDivisionError, ma non è possibile rilevare altre eccezioni.

divide(1, 0)
# catch ZeroDivisionError: division by zero

# divide('a', 'b')
# TypeError: unsupported operand type(s) for /: 'str' and 'str'

eseguire operazioni diverse a più eccezioni

È possibile specificare più clausole eccetto e impostare operazioni diverse per ciascuna eccezione.

def divide_each(a, b):
    try:
        print(a / b)
    except ZeroDivisionError as e:
        print('catch ZeroDivisionError:', e)
    except TypeError as e:
        print('catch TypeError:', e)

divide_each(1, 0)
# catch ZeroDivisionError: division by zero

divide_each('a', 'b')
# catch TypeError: unsupported operand type(s) for /: 'str' and 'str'

applicare la stessa operazione a più eccezioni

È possibile specificare più nomi di eccezioni come tuple in una clausola eccetto.

def divide_same(a, b):
    try:
        print(a / b)
    except (ZeroDivisionError, TypeError) as e:
        print(e)

divide_same(1, 0)
# division by zero

divide_same('a', 'b')
# unsupported operand type(s) for /: 'str' and 'str'

Cattura tutte le eccezioni

È anche possibile tutte le eccezioni senza specificare le eccezioni.

Carattere jolly tranne (escluso nudo)

Tutte le eccezioni possono essere rilevate omettendo il nome dell’eccezione dalla clausola escludono. Se sono presenti più clausole di eccezione, il nome dell’eccezione può essere omesso solo nell’ultima clausola di eccezione.

La clausola eccetto senza nomi di eccezioni è chiamata jolly eccetto, bare eccetto, ecc. Fare attenzione a usarla come descritto nella documentazione ufficiale.

L’ultima clausola eccetto può omettere il nome oi nomi dell’eccezione per fungere da carattere jolly. Usalo con estrema cautela, poiché in questo modo è facile mascherare un vero errore di programmazione!
8. Errori ed eccezioni – Gestione delle eccezioni — Documentazione Python 3.9.0

def divide_wildcard(a, b):
    try:
        print(a / b)
    except:
        print('Error')

divide_wildcard(1, 0)
# Error

divide_wildcard('a', 'b')
# Error

Ad eccezione dei caratteri jolly, vengono intercettate tutte le eccezioni, incluse SystemExit (rilevato da sys.exit(), ecc.) e KeyboardInterrupt (rilevato immettendo il tasto di interruzione Ctrl + C). In molti casi, è meglio terminare il processo senza intercettare queste eccezioni, quindi è meglio usare l’eccezione descritta di seguito.

Classe base:Exception

È possibile specificare Exception nella clausola exclude, che è la classe base per tutte le eccezioni integra non in uscita dal sistema.

def divide_exception(a, b):
    try:
        print(a / b)
    except Exception as e:
        print(e)

divide_exception(1, 0)
# division by zero

divide_exception('a', 'b')
# unsupported operand type(s) for /: 'str' and 'str'

La gerarchia delle classi per le eccezioni predefinite è la seguente.

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ...
      ...

Poiché SystemExit e KeyboardInterrupt non ereditano Exception, se Exception è specificata nella clausola exclude, sys.exit() e l’eccezione dell’input della chiave di interruzione non verrà rilevata.

Questa eccezione viene sollevata dalla funzione sys.exit(). Eredita da BaseException invece di Exception in modo che non venga catturato accidentalmente dal codice che intercetta Exception. Ciò consente all’eccezione di propagarsi correttamente e di far uscire l’interprete.
Eccezioni integrano – SystemExit – Documentazione Python 3.9.0

Generato quando l’utente preme il tasto di interruzione (normalmente Control-C o Elimina). Durante l’esecuzione, viene eseguito regolarmente un controllo delle interruzioni. L’eccezione da eredita BaseException in modo non essere catturata accidentalmente Exception e quindi da cattura dall’ereditarietà all’interprete di uscire.
Eccezioni integrano – KeyboardInterrupt – Documentazione Python 3.9.0

La classe base per tutte le eccezioni predefinite, inclusi SystemExit e KeyboardInterrupt, isBaseException. Se si specifica BaseException invece di Exception nella clausola eccetto, verranno intercettate tutte le eccezioni così come il carattere jolly eccetto.

È meglio specificare il più possibile le eccezioni previste nella clausola escludere perché la cattura di un’eccezione imprevista può causare anche un bug.

Esegui l’azione se nessuna eccezione:try ... except ... else ...

È possibile specificare l’azione da eseguire se non ci sono eccezioni nella clausola else. Se si verifica un’eccezione e viene intercettata da eccetto, l’azione nella clausola else non viene eseguita.

def divide_else(a, b):
    try:
        print(a / b)
    except ZeroDivisionError as e:
        print('catch ZeroDivisionError:', e)
    else:
        print('finish (no error)')

divide_else(1, 2)
# 0.5
# finish (no error)

divide_else(1, 0)
# catch ZeroDivisionError: division by zero

Azione di pulizia:try ... except ... finally ...

Nella clausola, infine, puoi specificare l’azione di pulizia da eseguire in questo dal fatto che si o meno un’eccezione.

def divide_finally(a, b):
    try:
        print(a / b)
    except ZeroDivisionError as e:
        print('catch ZeroDivisionError:', e)
    finally:
        print('all finish')

divide_finally(1, 2)
# 0.5
# all finish

divide_finally(1, 0)
# catch ZeroDivisionError: division by zero
# all finish

Puoi anche usare l’altro e la clausola infine insieme. Se non si verifica nessuna eccezione, viene eseguita la clausola else e quindi viene eseguita la clausolafinal.

def divide_else_finally(a, b):
    try:
        print(a / b)
    except ZeroDivisionError as e:
        print('catch ZeroDivisionError:', e)
    else:
        print('finish (no error)')
    finally:
        print('all finish')

divide_else_finally(1, 2)
# 0.5
# finish (no error)
# all finish

divide_else_finally(1, 0)
# catch ZeroDivisionError: division by zero
# all finish

Ignora le eccezioni:pass

Se vuoi catturare un’eccezione e passarla senza fare nulla, usa pass.

def divide_pass(a, b):
    try:
        print(a / b)
    except ZeroDivisionError:
        pass

divide_pass(1, 0)

Vedere il seguente articolo per i dettagli sulla dichiarazione di passaggio.

Esempio pratico: Lettura di file immagine

Un comodo esempio di utilizzo della gestione delle eccezioni è la lettura dei file di immagine.

Quello che segue è un esempio di ridimensionamento dei file di immagine nella cartella che utilizza Pillow.

Senza gestione delle eccezioni:

Ottieni tutti i percorsi file nella cartella con glob() e ridimensiona solo i file che insieme dei percorsi a specifiche.

import os
import glob
from PIL import Image

dst_dir = 'data/temp/images_half'
os.makedirs(dst_dir, exist_ok=True)
files = glob.glob('./data/temp/images/*')

for f in files:
    root, ext = os.path.splitext(f)
    if ext in ['.jpg', '.png']:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        basename = os.path.basename(root)
        img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))

Poiché i file immagine hanno varie estensioni, è difficile specificarle.

Con gestione delle eccezioni:

files = glob.glob('./data/temp/images/*')

for f in files:
    try:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        root, ext = os.path.splitext(f)
        basename = os.path.basename(root)
        img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))
    except OSError as e:
        pass

Tutti i file che possono essere aperti con Image.open() di Pillow vengono ridimensionati.

Lo stile che giudica vietare la condizione come la prima si chiama “LBYL: Look Before You Leap” e lo stile che utilizza la gestione delle eccezioni come la seconda si chiama “EAFP: Easier to Ask for Forgiveness than Permission”.

Entrambi hanno pro e contro, ma il processo che richiede molte condizioni può essere scritto in modo conciso utilizzando la gestione delle eccezioni.