Gestione delle eccezioni di cui non sono a conoscenza

5

Quando lavoro con la gestione delle eccezioni, noto che spesso devo confrontarmi con quelle di cui non avevo idea. Soprattutto è evidente quando programmo un metodo che acquisisce i dati dal web. Potrebbe verificarsi un errore, ad esempio, a causa della perdita di connessione, posso gestirlo. Ma poi si verifica un altro errore, un errore diverso con la stessa causa - perdita di connessione. Ok, l'ho aggiunto. A volte succede ancora un altro. Quindi, il problema è che non sono mai abbastanza sicuro se ho gestito tutti i possibili errori che potrebbero verificarsi a causa di una determinata causa.

In un primo momento, ho pensato di inserire caratteri jolly e fare qualcosa come (esempio in Python):

try:
    #do stuff
except:
    #handle error

Ma presto si è rivelato un approccio sbagliato, perché se devo gestire, ad esempio, KeyboardInterrupt , che viene generato quando un utente termina il programma, invece di essere gestito da un ambito, voglio che sia gestito da , è gestito da questo jolly, che non dovrebbe avere nulla a che fare con esso.

Quindi come gestisco le eccezioni che non conosco ma che potrebbero verificarsi (o non accadere)? Qualche tipo di exceptEverythingBut KeyboardInterrupt: ? Dubito che molte lingue lo abbiano nella loro sintassi.

EDIT1: un esempio davvero semplificato:

#!/usr/bin/python3 -u
# -*- coding: utf-8 -*-

try:
    while True:
        try:
            print(1)
        except:
            print(2)
except KeyboardInterrupt:
    print('end')

Quando premo Ctrl + C , voglio che stampi 'end' e finisca. Ma invece stampa 2 e continua l'esecuzione.

Se provo questo:

#!/usr/bin/python3 -u
# -*- coding: utf-8 -*-

try:
    while True:
        try:
            print(1)
        except KeyboardInterrupt:
            break
        except:
            print(2)
except KeyboardInterrupt:
    print('end')

termina, ma salta la% esterna% co_de e non stampa 'fine'. E non è quello che voglio. Quindi, l'unico modo che vedo è di impedire che l'ambito interno maneggi completamente except . Ma non è possibile se c'è un KeyboardInterrupt o except: lì. Quindi, ho bisogno di specificare esattamente quali errori voglio gestire all'interno except KeyboardInterrupt: . Ma, come ho detto all'inizio, non so sempre cosa possono essere.

Sto facendo questa domanda, perché il mio modo comune per farlo è lasciare che il programma fallisca inaspettatamente diverse volte, leggere i registri e aggiungere la gestione degli errori che non conoscevo nelle nuove versioni; tuttavia questo potrebbe essere solo un approccio ingenuo, quindi voglio sapere come è fatto da persone esperte.

    
posta Highstaker 27.01.2016 - 13:04
fonte

4 risposte

6

Risolvi l'eccezione solo quando la ottieni:

try:
  #do stuff
except KeyboardInterrupt:
  raise
except:
  #do other stuff

Specifica di ottenere un'eccezione che sai di voler gestire in modo diverso dal caso predefinito, ma non sai come gestirlo, quindi basta passarlo, rilanciandolo di nuovo.

Alcuni esempi di lavoro:

#!/usr/bin/python2

if __name__ == "__main__":
    try:
        while True:
            try:
                print(1)
            except KeyboardInterrupt:
                raise
            except:
                print(2)
    except KeyboardInterrupt:
        print('end')

Tieni presente che non devi utilizzare except: , in quanto questa è una cattiva pratica. except: utilizzato in questo esempio è utilizzato esclusivamente per rendere le cose il più semplici possibile.

    
risposta data 27.01.2016 - 14:07
fonte
8

In generale, non dovresti usare except: , tranne per alcune circostanze estremamente rare, in particolare log-and-reraise o al livello più alto dopo il quale il programma deve terminare. Non usarlo affatto nelle librerie o in qualsiasi metodo non di primo livello.

Invece, per favore usa except Exception: . Rileva la maggior parte degli errori "normali", tranne alcuni speciali ( KeyboardInterupt , "SystemExit" e alcuni altri). Vedi link .

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- ... (all other exceptions)

'' '

Nella maggior parte dei casi, consiglierei addirittura di non utilizzare except Exception: , e invece di scegliere i tipi di eccezione più specifici possibili. Questo perché cose come NameError , AttributeError , KeyError e simili sono tutte sottoclassi di Exception . Con questo puoi nascondere i bug (errori di battitura).

Quando si ha a che fare con le connessioni di rete, è molto probabile che si desideri utilizzare qualcosa come except socket.error: o except LibrarySpecificErrorHere . Controlla la gerarchia delle eccezioni per la libreria di rete che usi. Non devi necessariamente utilizzare le classi di eccezioni foglia.

Con una clausola except più ampia, altri bug saranno nascosti da essa. Quindi: avere il minor numero possibile di codice nel blocco try e avere le classi di eccezioni più specifiche possibili.

Considera questo:

bars = []
for foo in foos:
    try:
        bar = foo.bar
    except AttributeError:
        # Sometimes we get a 'foo' that does not have a 'bar' set yet.
        pass
    else:
        bar.apend(bar)

vs

bars = []
for foo in foos:
    try:
        bar = foo.bar
        bars.apend(bar)
    except AttributeError:
        # Sometimes we get a 'foo' that does not have a 'bar' set yet.
        pass

tu hai notato l'errore di ortografia in append (I 'accidentalmente' ha scritto apend ). Sei intelligente, quindi l'hai notato. Ma Python lo manca nel secondo caso, mentre nel primo caso l'ambito della gestione delle eccezioni è più piccolo, e quindi un bug era in agguato al di fuori dell'ambito di gestione, è uscito e l'hai visto.

Lo stesso vale per questo pezzo di codice:

bars = []
for foo in foos:
    try:
        bar = fo.bar
    except:
        # Sometimes we get a 'foo' that does not have a 'bar' set yet.
        pass
    else:
        bars.append(bar)

Oopsie, ho ignorato casualmente un NameError ?

Ancora: except: rileva le eccezioni tutte , anche quelle che non dovrebbero intercettare ( SystemExit , KeyboardInterupt , ...). In generale, l'applicazione dovrebbe essere morta dopo che una di queste eccezioni è stata sollevata. Sii molto specifico nella gestione delle eccezioni, assicurati che il minor numero possibile di bug venga nascosto da una gestione eccezionalmente aggressiva delle eccezioni.

    
risposta data 29.01.2016 - 00:45
fonte
0

Se si assegna una funzione di gestione degli errori personalizzata a sys.excepthook, verrà chiamata ogni volta che viene sollevata un'eccezione e non sarà necessario utilizzare un'istruzione try-except. Qualcosa del genere dovrebbe funzionare:

import sys

def on_error(etype, value, tb):
    if etype == KeyboardInterrupt:
        return
    # handle other types of errors

sys.excepthook = on_error
    
risposta data 29.01.2016 - 15:37
fonte
-4

E questo è il motivo per cui mi piace Java - non ci sono sorprese del genere (ogni funzione esplicitamente ti dice quali eccezioni potrebbe generare).

Non sarebbe qualcosa di simile?

try:
    #do stuff
except(KeyboardInterrupt):
    pass
else:
    #handle error
    
risposta data 27.01.2016 - 13:12
fonte

Leggi altre domande sui tag