Devo sempre specificare un tipo di eccezione nelle istruzioni "tranne"?


93

Quando si utilizza PyCharm IDE, l'utilizzo di except:senza un tipo di eccezione attiva un promemoria dall'IDE che questa clausola di eccezione è Too broad.

Dovrei ignorare questo consiglio? O è Pythonic specificare sempre il tipo di eccezione?


Se vuoi saperne di più su questo rispetto alle risposte, Google ingoia le eccezioni. Puoi insieme a loro tutti i tipi di altre cose interessanti da fare e da non fare. Il codice odora è un altro.
Tony Hopkinson

Risposte:


89

È quasi sempre meglio specificare un tipo di eccezione esplicita. Se usi una except:clausola nuda , potresti finire per rilevare eccezioni diverse da quelle che ti aspetti di catturare: questo può nascondere bug o rendere più difficile il debug dei programmi quando non fanno ciò che ti aspetti.

Ad esempio, se stai inserendo una riga in un database, potresti voler rilevare un'eccezione che indica che la riga esiste già, in modo da poter eseguire un aggiornamento.

try:
    insert(connection, data)
except:
    update(connection, data)

Se si specifica un bare except:, si rileverà anche un errore di socket che indica che il server del database è caduto. È meglio rilevare solo le eccezioni che sai come gestire: spesso è meglio che il programma fallisca nel punto dell'eccezione piuttosto che continuare ma comportarsi in modi strani e inaspettati.

Un caso in cui potresti voler utilizzare un bare except:è al livello più alto di un programma che devi sempre essere in esecuzione, come un server di rete. Ma poi, devi stare molto attento a registrare le eccezioni, altrimenti sarà impossibile capire cosa non va. Fondamentalmente, dovrebbe esserci al massimo un solo posto in un programma che fa questo.

Un corollario di tutto ciò è che il tuo codice non dovrebbe mai funzionare raise Exception('some message')perché impone l'uso del codice client except:(o except Exception:che è quasi altrettanto cattivo). È necessario definire un'eccezione specifica per il problema che si desidera segnalare (magari ereditando da una sottoclasse di eccezioni incorporata come ValueErroro TypeError). Oppure dovresti sollevare una specifica eccezione incorporata. Ciò consente agli utenti del codice di prestare attenzione nel cogliere solo le eccezioni che desiderano gestire.


7
+1 Molto vero. Ancora più divertente con l'esempio: except:cattura anche (tra molte altre cose) NameErrore AttributeError, quindi se sbagli qualcosa nel tryblocco (ad esempio la tua funzione "inserisci" viene effettivamente chiamata insert_oneperché qualcuno non ha valutato la coerenza quanto dovrebbe), cerca sempre di farlo in silenzio update().

1
E quando è necessario assicurarsi che un'eccezione non venga generata sopra il sito della chiamata corrente? Ad esempio, ho rilevato tutte le eccezioni specifiche che posso prevedere vengano lanciate, ora devo aggiungere che "se questa cosa a cui non ho pensato viene lanciata, devo registrarla prima che uccida il contesto di esecuzione in esecuzione" (come main())?
Adam Parkin

Questo è il tipo di situazione di cui parlo nel paragrafo che inizia con "Un caso ...". A volte è sicuramente necessario, ma ogni programma dovrebbe avere solo un posto che lo fa. E devi stare attento che sia chiaro nel registro cosa sta succedendo, altrimenti avrai un tempo frustrante cercando di capire perché il tuo programma non gestisce correttamente l'evento / richiesta / qualsiasi cosa.
babbageclunk

3
@delnan: peggio di così. except Exception:catturerà NameErrore AttributeErroranche. Ciò che rende nudo except:così male è che cattura cose che non hanno motivo di essere scoperte , ad esempio SystemExit(sollevato quando chiami exito sys.exit, e ora hai impedito un'uscita prevista) e KeyboardInterrupt(di nuovo, se l'utente preme Ctrl-C, probabilmente non vuoi continuare a correre solo per far loro dispetto). Solo quest'ultimo ha senso da catturare e dovrebbe essere catturato esplicitamente. Almeno except Exception:lascia che quei due si propagino normalmente.
ShadowRanger

38

Non dovresti ignorare il consiglio che ti dà l'interprete.

Dalla Guida allo stile PEP-8 per Python:

Quando si individuano le eccezioni, menzionare eccezioni specifiche ogni volta che è possibile invece di utilizzare una semplice clausola tranne:.

Ad esempio, usa:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

Una semplice clausola tranne: catturerà le eccezioni SystemExit e KeyboardInterrupt, rendendo più difficile interrompere un programma con Control-C e può mascherare altri problemi. Se vuoi catturare tutte le eccezioni che segnalano errori di programma, usa tranne Eccezione: (nudo eccetto equivale a tranne BaseException :).

Una buona regola pratica è limitare l'uso di clausole "tranne" a due casi:

Se il gestore delle eccezioni stamperà o registrerà il traceback; almeno l'utente saprà che si è verificato un errore. Se il codice deve eseguire un po 'di lavoro di pulizia, ma lascia che l'eccezione si propaghi verso l'alto con raise. provare ... finalmente può essere un modo migliore per gestire questo caso.



9

Non specifico per Python questo.

Il punto centrale delle eccezioni è affrontare il problema il più vicino possibile a dove è stato causato.

Quindi mantieni il codice che potrebbe in circostanze eccezionali potrebbe innescare il problema e la risoluzione "uno accanto all'altro".

Il fatto è che non puoi conoscere tutte le eccezioni che potrebbero essere generate da un pezzo di codice. Tutto quello che puoi sapere è che se si tratta di un'eccezione di file non trovato, potresti intercettarlo e chiedere all'utente di ottenerne uno che esegue o annulla la funzione.

Se metti try catch in giro, non importa quale problema ci fosse nella tua routine di file (sola lettura, permessi, UAC, non proprio un pdf, ecc.), Tutti cadranno nel tuo file not found catch, e il tuo utente sta urlando "ma c'è, questo codice fa schifo"

Ora ci sono un paio di situazioni in cui potresti prendere tutto, ma dovrebbero essere scelte consapevolmente.

Vengono catturati, annullati alcune azioni locali (come la creazione o il blocco di una risorsa (ad esempio l'apertura di un file su disco per la scrittura), quindi si lancia di nuovo l'eccezione, per essere affrontati a un livello superiore)

L'altro è che non ti interessa perché è andato storto. Ad esempio la stampa. Potresti avere un problema a tutto tondo, per dire C'è qualche problema con la tua stampante, per favore risolvilo e non uccidere l'applicazione a causa di ciò. Se il tuo codice eseguisse una serie di attività separate utilizzando una sorta di pianificazione, non vorresti che l'intera cosa muoia, perché una delle attività non è riuscita.

Nota Se si esegue quanto sopra, non posso raccomandare un qualche tipo di registrazione delle eccezioni, ad esempio, prova abbastanza bene il catch log end.


Direi che si tratta di equilibrio. Devi cogliere l'eccezione abbastanza presto per essere in grado di riprenderti e abbastanza tardi per sapere dove andare con essa. Ecco perché la gestione delle eccezioni Java causa un tale caos, perché devi reinserire l'eccezione ad ogni passaggio e perdi informazioni.
discesa

2
+1 per "non ti interessa perché è andato storto". Lo sto usando in diversi punti attorno a una singola riga di codice in cui analizzo una data / ora da un URL. La libreria di analisi di data / ora di terze parti non elenca tutte le eccezioni che può lanciare (ho trovato OverflowError e TypeError oltre allo standard ValueError, ma probabilmente ce ne sono di più), e comunque non mi interessa davvero perché è stata lanciata un'eccezione, voglio solo fornire un messaggio di errore ragionevole all'utente che dice che qualcosa non va con la data / ora.
Michael Rodby

3

Prenderai anche, ad esempio, Control-C con quello, quindi non farlo a meno che non lo "lanci" di nuovo. Tuttavia, in quel caso dovresti usare piuttosto "finalmente".


3

Specificare sempre il tipo di eccezione, ci sono molti tipi non si vuole prendere, come SyntaxError, KeyboardInterrupt, MemoryErroretc.


2
utilizzando except Exception:eviteremmo i tipi di cui sopra che non vogliamo catturare?
HorseloverFat

except Exceptionè ok.
Ulrich Eckhardt

4
@HorseloverFat: except Exceptioncattura SyntaxErrore MemoryErrorperché è la loro classe base. KeyboardInterrupt, SystemExit(generato da sys.exit()) non vengono catturati (sono sottoclassi BaseException immediate)
jfs

suona come se non fosse l'ideale allora - meglio specificare più precisamente.
HorseloverFat

3

Ecco i luoghi in cui uso tranne che senza il tipo

  1. prototipazione rapida e sporca

Questo è l'uso principale nel mio codice per le eccezioni non controllate

  1. funzione main () di primo livello, dove registro ogni eccezione non rilevata

Aggiungo sempre questo, in modo che il codice di produzione non versi stacktrace

  1. tra i livelli dell'applicazione

Ho due modi per farlo:

  • Primo modo per farlo: quando un livello di livello superiore chiama una funzione di livello inferiore, racchiude le chiamate in eccezioni digitate per gestire le eccezioni di livello inferiore "superiore". Ma aggiungo un'istruzione tranne generica, per rilevare eccezioni di livello inferiore non gestite nelle funzioni di livello inferiore.

Preferisco così, trovo più facile rilevare quali eccezioni avrebbero dovuto essere rilevate in modo appropriato: "vedo" meglio il problema quando un'eccezione di livello inferiore viene registrata da un livello superiore

  • Secondo modo per farlo: ogni funzione di livello superiore dei livelli di livello inferiore ha il proprio codice racchiuso in un generico tranne, per catturare tutte le eccezioni non gestite su quel livello specifico.

Alcuni colleghi preferiscono questo modo, poiché mantiene le eccezioni di livello inferiore nelle funzioni di livello inferiore, a cui "appartengono".


-14

Prova questo:

try:
    #code
except ValueError:
    pass

Ho ricevuto la risposta da questo link, se qualcun altro si imbatte in questo problema , dai un'occhiata

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.