Perché "tranne: passare" è una cattiva pratica di programmazione?


325

Vedo spesso commenti su altre domande di Stack Overflow su come l'uso di except: passè scoraggiato. Perché è così male? A volte non mi interessa quali siano gli errori e voglio solo continuare con il codice.

try:
    something
except:
    pass

Perché usare un except: passblocco non va bene? Cosa lo rende cattivo? È il fatto che ho passun errore o che ho exceptqualche errore?


1
Per lo meno, ti suggerirei di registrarlo, quindi SAPI quali problemi stai ignorando. Utilizzare il loggingmodulo a livello di DEBUG per evitarli di eseguire lo streaming in produzione, ma tenerli disponibili in fase di sviluppo.
pcurry

Risposte:


346

Come hai indovinato correttamente, ci sono due lati: catturare qualsiasi errore specificando dopo nessun tipo di eccezione excepte semplicemente passandolo senza intraprendere alcuna azione.

La mia spiegazione è "un po 'più lunga", quindi tl; dr si scompone in questo modo:

  1. Non cogliere alcun errore . Specifica sempre da quali eccezioni sei pronto a recuperare e cattura solo quelle.
  2. Cerca di evitare di passare tranne i blocchi . Se non esplicitamente desiderato, questo di solito non è un buon segno.

Ma andiamo nel dettaglio:

Non cogliere alcun errore

Quando si utilizza un tryblocco, di solito lo si fa perché si sa che esiste la possibilità che venga generata un'eccezione. Pertanto, hai già un'idea approssimativa di ciò che può rompersi e quale eccezione può essere lanciata. In tali casi, si rileva un'eccezione perché è possibile recuperarlo positivamente . Ciò significa che sei preparato per l'eccezione e hai un piano alternativo che seguirai in caso di tale eccezione.

Ad esempio, quando si chiede all'utente di inserire un numero, è possibile convertire l'input utilizzando int()quale potrebbe sollevare un ValueError. Puoi facilmente recuperarlo semplicemente chiedendo all'utente di riprovare, quindi catturare ValueErrore sollecitare nuovamente l'utente sarebbe un piano appropriato. Un esempio diverso potrebbe essere se si desidera leggere alcune configurazioni da un file e quel file non esiste. Poiché si tratta di un file di configurazione, potresti avere una configurazione predefinita come fallback, quindi il file non è esattamente necessario. Quindi catturare un FileNotFoundErrore semplicemente applicare la configurazione predefinita sarebbe un buon piano qui. Ora in entrambi questi casi, abbiamo un'eccezione molto specifica che ci aspettiamo e abbiamo un piano altrettanto specifico per riprenderci. Come tale, in ogni caso, abbiamo esplicitamente solo except questo eccezione.

Tuttavia, se dovessimo catturare tutto , allora - oltre a quelle eccezioni da cui siamo pronti a riprenderci - c'è anche la possibilità che otteniamo eccezioni che non ci aspettavamo e da cui non possiamo effettivamente recuperare; o non dovrebbe riprendersi da.

Facciamo l'esempio del file di configurazione dall'alto. In caso di file mancante, abbiamo appena applicato la nostra configurazione predefinita e potremmo decidere in un secondo momento di salvare automaticamente la configurazione (quindi la prossima volta il file esiste). Ora immagina di ottenere un IsADirectoryError, o unPermissionErroranziché. In tali casi, probabilmente non vogliamo continuare; potremmo ancora applicare la nostra configurazione predefinita, ma in seguito non saremo in grado di salvare il file. Ed è probabile che anche l'utente intendesse avere una configurazione personalizzata, quindi è probabile che non si desideri utilizzare i valori predefiniti. Quindi vorremmo parlarne immediatamente all'utente e probabilmente interrompere anche l'esecuzione del programma. Ma non è qualcosa che vogliamo fare da qualche parte in profondità all'interno di una piccola parte di codice; questo è qualcosa di importante a livello di applicazione, quindi dovrebbe essere gestito in alto, quindi lasciate che l'eccezione si gonfi.

Un altro semplice esempio è anche menzionato nel documento di idiomi di Python 2 . Qui, nel codice esiste un semplice errore di battitura che provoca l'interruzione. Poiché stiamo rilevando ogni eccezione, rileviamo anche NameErrors e SyntaxErrors . Entrambi sono errori che accadono a tutti noi durante la programmazione; ed entrambi sono errori che non vogliamo assolutamente includere quando spediamo il codice. Ma poiché abbiamo anche catturato quelli, non sapremo nemmeno che si sono verificati lì e perderebbero qualsiasi aiuto per eseguire il debug correttamente.

Ma ci sono anche eccezioni più pericolose per le quali probabilmente non siamo preparati. Ad esempio SystemError è di solito qualcosa che accade raramente e che non possiamo davvero pianificare; significa che sta succedendo qualcosa di più complicato, qualcosa che probabilmente ci impedisce di continuare l'attività corrente.

In ogni caso, è molto improbabile che tu sia preparato a tutto in una piccola parte del codice, quindi è lì che dovresti solo catturare le eccezioni per le quali sei preparato. Alcune persone suggeriscono di catturare almeno Exceptionperché non includerà cose come SystemExite KeyboardInterruptche, di progettazione, devono chiudere l'applicazione, ma direi che questo è ancora troppo poco specifico. C'è solo un posto in cui accetto personalmente la cattura Exceptiono semplicemente qualsiasieccezione, vale a dire in un unico gestore di eccezioni a livello di applicazione globale che ha il solo scopo di registrare qualsiasi eccezione per la quale non eravamo preparati. In questo modo, possiamo ancora conservare quante più informazioni sulle eccezioni impreviste, che possiamo quindi utilizzare per estendere il nostro codice per gestirle esplicitamente (se riusciamo a recuperarle) o, in caso di un bug, per creare casi di test per assicurarci non succederà più. Ma, naturalmente, funziona solo se abbiamo colto solo le eccezioni che già ci aspettavamo, quindi quelle che non ci aspettavamo salteranno naturalmente.

Cerca di evitare di passare tranne i blocchi

Quando si coglie esplicitamente una piccola selezione di eccezioni specifiche, ci sono molte situazioni in cui andremo bene semplicemente non facendo nulla. In questi casi, solo avere except SomeSpecificException: passva bene. Il più delle volte, tuttavia, non è così, poiché probabilmente abbiamo bisogno di un po 'di codice relativo al processo di recupero (come menzionato sopra). Questo può essere, ad esempio, qualcosa che ritenta nuovamente l'azione, o invece impostare un valore predefinito.

In caso contrario, ad esempio perché il nostro codice è già strutturato per essere ripetuto fino a quando non ha esito positivo, il passaggio è sufficiente. Prendendo il nostro esempio dall'alto, potremmo voler chiedere all'utente di inserire un numero. Poiché sappiamo che agli utenti piace non fare ciò che chiediamo loro, potremmo semplicemente metterlo in un ciclo in primo luogo, quindi potrebbe apparire così:

def askForNumber ():
    while True:
        try:
            return int(input('Please enter a number: '))
        except ValueError:
            pass

Poiché continuiamo a provare fino a quando non viene generata alcuna eccezione, non abbiamo bisogno di fare nulla di speciale nel blocco tranne, quindi va bene. Ma, naturalmente, si potrebbe sostenere che almeno vogliamo mostrare all'utente un messaggio di errore per dirgli perché deve ripetere l'input.

In molti altri casi, tuttavia, il semplice passaggio di un exceptsegno indica che non eravamo davvero preparati all'eccezione che stiamo rilevando. A meno che tali eccezioni non siano semplici (come ValueErroro TypeError) e il motivo per cui possiamo passare sia ovvio, cerca di evitare di passare. Se non c'è davvero niente da fare (e ne sei assolutamente sicuro), allora considera di aggiungere un commento perché è così; in caso contrario, espandere il blocco di esclusione per includere effettivamente un codice di ripristino.

except: pass

Il peggior trasgressore però è la combinazione di entrambi. Ciò significa che stiamo rilevando volontariamente qualsiasi errore, anche se non siamo assolutamente preparati per questo e non facciamo nulla al riguardo. È almeno desidera registrare l'errore e anche probabile che reraise per terminare ancora l'applicazione (è improbabile è possibile continuare come normale dopo un MemoryError). Il solo passaggio non solo manterrà l'applicazione in qualche modo viva (a seconda di dove catturi, ovviamente), ma eliminerà anche tutte le informazioni, rendendo impossibile scoprire l'errore, il che è particolarmente vero se non sei tu a scoprirlo.


Quindi la linea di fondo è: prendi solo le eccezioni che davvero ti aspetti e da cui sei pronto a recuperare; tutti gli altri sono probabilmente errori che dovresti correggere o comunque qualcosa per cui non sei preparato. Passare eccezioni specifiche va bene se davvero non hai bisogno di fare qualcosa al riguardo. In tutti gli altri casi, è solo un segno di presunzione ed essere pigri. E sicuramente vuoi risolverlo.


1
"Almeno vuoi registrare l'errore e probabilmente anche rilanciarlo per terminare ancora l'applicazione". Puoi dimostrare come "rilanciare" un'eccezione per farla ribollire anche dopo averla catturata? Mi sembra utile aggiungere alcuni messaggi di errore personalizzati lasciando che l'eccezione imponga la chiusura dell'applicazione.
Gabriel Staples,

1
Questo aiuta a chiarire: usano la coperta except, ma poi chiamano raisesenza argomenti per continuare a far apparire l'eccezione, terminando l'applicazione. Mi piace: ianbicking.org/blog/2007/09/re-raising-exceptions.html . Sembra una solida eccezione alla regola di non usare la coperta except.
Gabriel Staples,

1
@GabrielStaples Sì, un'eccezione rilevata può essere riproposta usando raise. In genere, tuttavia, lo si farebbe solo in alcune posizioni dell'applicazione per registrare l'eccezione.
colpì il

Questo è fantastico, evitare di passare tranne i blocchi. Direi che fai tutto ciò che sembra più comprensibile, specialmente agli altri. Ottieni una seconda serie di occhi di pitone per rivedere il tuo codice e vedere se mettono in discussione il blocco. La leggibilità è la chiave.
Radtek,

262

Il problema principale qui è che ignora tutto e tutti gli errori: memoria insufficiente, CPU in fase di masterizzazione, l'utente vuole fermarsi, il programma vuole uscire, Jabberwocky sta uccidendo gli utenti.

Questo è troppo. Nella tua testa, stai pensando "Voglio ignorare questo errore di rete". Se qualcosa di imprevisto va storto, il codice continua silenziosamente e si rompe in modi completamente imprevedibili che nessuno può eseguire il debug.

Ecco perché dovresti limitarti a ignorare specificamente solo alcuni errori e lasciare che il resto passi.


75

L'esecuzione letterale del tuo pseudo codice non dà nemmeno alcun errore:

try:
    something
except:
    pass

come se fosse un pezzo di codice perfettamente valido, invece di lanciare a NameError. Spero che questo non sia quello che vuoi.


51

Perché "tranne: passare" è una cattiva pratica di programmazione?

Perché è così male?

try:
    something
except:
    pass

Questo cattura ogni possibile eccezione, incluso GeneratorExit, KeyboardInterrupte SystemExit- che sono eccezioni che probabilmente non intendi cogliere. È come catturare BaseException.

try:
    something
except BaseException:
    pass

Le versioni precedenti della documentazione dicono :

Poiché ogni errore in Python solleva un'eccezione, l'utilizzo except:può far apparire molti errori di programmazione come problemi di runtime, il che ostacola il processo di debug.

Gerarchia delle eccezioni di Python

Se si rileva una classe di eccezione padre, vengono rilevate anche tutte le classi secondarie. È molto più elegante catturare solo le eccezioni che sei disposto a gestire.

Ecco la gerarchia delle eccezioni di Python 3 : vuoi davvero prenderli tutti ?:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
           +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Non farlo

Se stai utilizzando questa forma di gestione delle eccezioni:

try:
    something
except: # don't just do a bare except!
    pass

Quindi non sarai in grado di interrompere il somethingblocco con Ctrl-C. Il programma trascurerà ogni possibile eccezione all'interno del tryblocco di codice.

Ecco un altro esempio che avrà lo stesso comportamento indesiderato:

except BaseException as e: # don't do this either - same as bare!
    logging.info(e)

Invece, prova a catturare solo l'eccezione specifica che sai che stai cercando. Ad esempio, se sai che potresti ricevere un errore di valore su una conversione:

try:
    foo = operation_that_includes_int(foo)
except ValueError as e:
    if fatal_condition(): # You can raise the exception if it's bad,
        logging.info(e)   # but if it's fatal every time,
        raise             # you probably should just not catch it.
    else:                 # Only catch exceptions you are prepared to handle.
        foo = 0           # Here we simply assign foo to 0 and continue. 

Ulteriore spiegazione con un altro esempio

Potresti farlo perché hai eseguito il web scraping e hai detto, a UnicodeError, ma poiché hai utilizzato la più ampia cattura di eccezioni, il tuo codice, che potrebbe avere altri difetti fondamentali, tenterà di completarsi, sprecando larghezza di banda , tempo di elaborazione, usura delle apparecchiature, memoria insufficiente, raccolta di dati inutili, ecc.

Se altre persone ti chiedono di completare in modo che possano fare affidamento sul tuo codice, capisco che mi sento costretto a gestire tutto. Ma se sei disposto a fallire rumorosamente mentre ti sviluppi, avrai l'opportunità di correggere i problemi che potrebbero comparire solo in modo intermittente, ma che sarebbero bug costosi a lungo termine.

Con una gestione degli errori più precisa, il codice può essere più robusto.


31
>>> import this

Lo Zen di Python, di Tim Peters

Bello è meglio che brutto.
Esplicito è meglio che implicito.
Semplice è meglio di complesso.
Complesso è meglio che complicato.
Flat è meglio di nidificato.
Sparse è meglio che denso.
La leggibilità conta.
I casi speciali non sono abbastanza speciali da infrangere le regole.
Sebbene la praticità superi la purezza.
Gli errori non dovrebbero mai passare silenziosamente.
A meno che non sia esplicitamente messo a tacere.
Di fronte all'ambiguità, rifiuta la tentazione di indovinare.
Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo.
Anche se in quel modo all'inizio potrebbe non essere ovvio a meno che tu non sia olandese.
Adesso è meglio che mai.
Anche se spesso non è mai meglio diproprio ora
Se l'implementazione è difficile da spiegare, è una cattiva idea.
Se l'implementazione è facile da spiegare, potrebbe essere una buona idea.
Gli spazi dei nomi sono un'ottima idea per suonare il clacson: facciamo di più!

Quindi, ecco la mia opinione. Ogni volta che trovi un errore, dovresti fare qualcosa per gestirlo, cioè scriverlo nel file di log o qualcos'altro. Almeno, ti informa che c'era un errore.


64
-1 L'argomento dell'autorità in realtà non spiega nulla. L'autorità può avere torto.
Izkata,

23
cosa ha scritto @Izkata, E, una riga sotto di essa, la stessa autorità scrive: "A meno che non sia esplicitamente messo a tacere", che è esattamente ciò che tranne: passa.
Ofri Raviv,

13
@OfriRaviv No, l'errore non sta passando implicitamente ? Richiederebbe esplicitamente la denominazione dell'errore che dovrebbe passare silenziosamente, ovvero essere esplicito al riguardo . Questo non è ciò tranne: passa.
Chelonian,

24

Dovresti usare almeno except Exception:per evitare di rilevare eccezioni di sistema come SystemExito KeyboardInterrupt. Ecco il link ai documenti.

In generale, è necessario definire esplicitamente le eccezioni che si desidera acquisire, per evitare di rilevare eccezioni indesiderate. Dovresti sapere quali eccezioni ignori .


13

Innanzitutto, viola due principi di Zen of Python :

  • Esplicito è meglio che implicito
  • Gli errori non dovrebbero mai passare silenziosamente

Ciò significa che intenzionalmente fai passare silenziosamente il tuo errore. Inoltre, non si sa quale errore si è verificato esattamente, perché except: passcatturerà qualsiasi eccezione.

In secondo luogo, se proviamo a sottrarci allo Zen di Python e parlare in termini di giusta sanità mentale, dovresti sapere che l'uso except:passti lascia senza conoscenza e controllo nel tuo sistema. La regola empirica è sollevare un'eccezione, se si verifica un errore, e intraprendere le azioni appropriate. Se non sai in anticipo quali azioni dovrebbero essere, registra almeno l'errore da qualche parte (e meglio aumentare nuovamente l'eccezione):

try:
    something
except:
    logger.exception('Something happened')

Ma, di solito, se provi a cogliere qualche eccezione, probabilmente stai facendo qualcosa di sbagliato!


2
... A meno che non sia esplicitamente messo a tacere, come nel caso di OP.
Iperboro,

Voglio conoscere la tua soluzione. In effetti, quando davvero nulla ha bisogno di fare, elencherò semplicemente gli errori tranne e faccio commenti e scrivo registri. Quindi passa.
Booster

2
@Hyperboreus, non credo, che catturare tutti e tutti gli errori li stia esplicitamente mettendo a tacere, cioè, non sai nemmeno, cosa catturi.
Alexander Zhukov,

13
"Perché qualcuno lo dice" non è davvero una risposta a un "Perché?" domanda.
Sebastian Negraszus,

12

Il except:passcostrutto essenzialmente silenzia qualsiasi condizione eccezionale che si presenta mentre try:viene eseguito il codice coperto nel blocco.

Ciò che rende questa cattiva pratica è che di solito non è quello che vuoi davvero. Più spesso, sta sorgendo una condizione specifica che si desidera mettere a tacere, ed except:passè troppo uno strumento contundente. Farà il lavoro fatto, ma maschererà anche altre condizioni di errore che probabilmente non hai previsto, ma che potresti voler affrontare in qualche altro modo.

Ciò che rende questo particolarmente importante in Python è che, secondo gli idiomi di questo linguaggio, le eccezioni non sono necessariamente errori . Sono spesso usati in questo modo, ovviamente, proprio come nella maggior parte delle lingue. Ma Python in particolare li ha occasionalmente utilizzati per implementare un percorso di uscita alternativo da alcune attività di codice che non fa realmente parte del normale caso in esecuzione, ma è ancora noto che si presenta di tanto in tanto e che ci si può aspettare anche nella maggior parte dei casi. SystemExitè già stato menzionato come un vecchio esempio, ma l'esempio più comune al giorno d'oggi potrebbe essere StopIteration. L'uso delle eccezioni in questo modo ha causato molte controversie, soprattutto quando gli iteratori e i generatori sono stati introdotti per la prima volta in Python, ma alla fine l'idea ha prevalso.


12

Il motivo n. 1 è già stato dichiarato: nasconde errori che non ti aspettavi.

(# 2) - Rende il tuo codice difficile da leggere e capire per gli altri. Se si rileva FileNotFoundException quando si sta tentando di leggere un file, è abbastanza ovvio per un altro sviluppatore quale funzionalità dovrebbe avere il blocco "catch". Se non si specifica un'eccezione, è necessario aggiungere ulteriori commenti per spiegare cosa dovrebbe fare il blocco.

(# 3) - Dimostra una programmazione pigra. Se usi il generico try / catch, indica che non capisci i possibili errori di runtime nel tuo programma o che non sai quali eccezioni sono possibili in Python. La cattura di un errore specifico mostra che hai compreso sia il tuo programma sia la gamma di errori che Python genera. Ciò è più probabile che altri sviluppatori e revisori del codice si fidino del tuo lavoro.


12

Quindi, quale output produce questo codice?

fruits = [ 'apple', 'pear', 'carrot', 'banana' ]

found = False
try:
     for i in range(len(fruit)):
         if fruits[i] == 'apple':
             found = true
except:
     pass

if found:
    print "Found an apple"
else:
    print "No apples in list"

Ora immagina che il blocco try- exceptsia centinaia di linee di chiamate a una complessa gerarchia di oggetti, ed è esso stesso chiamato nel mezzo dell'albero delle chiamate di un grande programma. Quando il programma non funziona, da dove inizi a cercare?


5
Ehm, grazie alle persone che hanno "corretto" questo, ma per favore non farlo - è intenzionalmente sbagliato, nel senso della "domanda dell'intervista". È forse più sottile di come appaia per la prima volta: provalo. Il mio punto è che schiacciare le eccezioni "tutte", specialmente in Python, rende difficile il debug, anche in una banale dozzina di righe di codice.
Ian Harvey,

11

In generale, puoi classificare qualsiasi errore / eccezione in una delle tre categorie :

  • Fatale : non è colpa tua, non puoi prevenirli, non puoi recuperarli. Non dovresti certamente ignorarli e continuare e lasciare il tuo programma in uno stato sconosciuto. Lascia che l'errore termini il tuo programma, non c'è niente che tu possa fare.

  • Boneheaded : colpa tua, molto probabilmente a causa di una supervisione, un bug o un errore di programmazione. Dovresti correggere il bug. Ancora una volta, sicuramente non dovresti ignorare e continuare.

  • Esogeno : è possibile aspettarsi questi errori in situazioni eccezionali, come file non trovato o connessione interrotta . Dovresti gestire esplicitamente questi errori e solo questi.

In tutti i casi except: pass, il tuo programma verrà lasciato in uno stato sconosciuto, dove potrebbe causare più danni.


6

In poche parole, se viene generata un'eccezione o un errore, qualcosa non va. Potrebbe non essere qualcosa di molto sbagliato, ma la creazione, il lancio e la cattura di errori ed eccezioni solo per il gusto di utilizzare le istruzioni goto non è una buona idea, e raramente viene eseguita. Il 99% delle volte, si è verificato un problema da qualche parte.

I problemi devono essere affrontati. Proprio come è nella vita, nella programmazione, se lasci solo i problemi e cerchi di ignorarli, non vanno via da soli molte volte; invece si ingrandiscono e si moltiplicano. Per evitare che un problema cresca su di te e colpisca ancora più avanti, o) 1) eliminalo e ripulisci il disordine in seguito, oppure 2) contenerlo e ripulisci il disordine in seguito.

Ignorare eccezioni ed errori e lasciarli così è un buon modo per sperimentare perdite di memoria, connessioni di database eccezionali, blocchi inutili sui permessi dei file, ecc.

In rare occasioni, il problema è così minuscolo, banale e - a parte la necessità di un tentativo ... cattura blocco - autonomo , che non c'è davvero nessun disordine da ripulire in seguito. Queste sono le uniche occasioni in cui questa best practice non si applica necessariamente. Nella mia esperienza, ciò ha generalmente significato che qualsiasi cosa il codice stia facendo è fondamentalmente meschina e trascurabile, e qualcosa come tentativi di tentativi o messaggi speciali non vale né la complessità né regge il thread.

Nella mia azienda, la regola è quasi sempre fare qualcosa in un blocco di cattura, e se non fai nulla, devi sempre inserire un commento con un'ottima ragione perché no. Non devi mai passare o lasciare un blocco di cattura vuoto quando c'è qualcosa da fare.


6

Secondo me gli errori hanno una ragione per apparire, che il mio suono sembra stupido, ma è così. Una buona programmazione genera errori solo quando devi gestirli. Inoltre, come ho letto qualche tempo fa, "l'istruzione pass è un'istruzione che mostra che il codice verrà inserito in un secondo momento", quindi se vuoi avere un'istruzione vuota vuota sentiti libero di farlo, ma per un buon programma ci sarà essere una parte mancante. perché non gestisci le cose che dovresti avere. Apparire eccezioni ti dà la possibilità di correggere i dati di input o di modificare la struttura dei dati in modo che tali eccezioni non si verifichino più (ma nella maggior parte dei casi (Eccezioni di rete, Eccezioni di input generali) le eccezioni indicano che le parti successive del programma non funzioneranno bene. Ad esempio, NetworkException può indicare una connessione di rete interrotta e il programma non può inviare / ricevere dati nelle fasi successive del programma.

Ma l'uso di un blocco pass per un solo blocco di esecuzione è valido, perché si differenzia ancora tra i tipi di eccezioni, quindi se si inseriscono tutti i blocchi di eccezioni in uno, non è vuoto:

try:
    #code here
except Error1:
    #exception handle1

except Error2:
    #exception handle2
#and so on

può essere riscritto in questo modo:

try:
    #code here
except BaseException as e:
    if isinstance(e, Error1):
        #exception handle1

    elif isinstance(e, Error2):
        #exception handle2

    ...

    else:
        raise

Quindi anche più blocchi di eccezione con pass-statement possono generare codice, la cui struttura gestisce tipi speciali di eccezioni.


4

Tutti i commenti fatti finora sono validi. Ove possibile, è necessario specificare quale eccezione esatta si desidera ignorare. Ove possibile, è necessario analizzare ciò che ha causato l'eccezione e ignorare solo ciò che si intendeva ignorare, e non il resto. Se l'eccezione fa sì che l'applicazione si "arresti in modo spettacolare", allora sia, perché è molto più importante sapere l'imprevisto accaduto quando è successo, piuttosto che nascondere il problema.

Detto questo, non prendere alcuna pratica di programmazione come fondamentale. Questo è stupido C'è sempre il tempo e il luogo per fare il blocco ignore-all-exceptions.

Un altro esempio di fondamentale idiota è l'uso gotodell'operatore. Quando ero a scuola, il nostro professore ci ha insegnato gotooperatore solo per menzionare che non lo userai MAI. Non credere alle persone che ti dicono che xyz non dovrebbe mai essere usato e non ci può essere uno scenario quando è utile. C'è sempre.


1
Il caso "goto" è stilistico e una questione di opinione, mentre "tranne: pass" di solito è effettivamente errato. Presuppone che se qualcuno dovesse, ad esempio, "uccidere -TERM" il processo a quel punto, dovrebbe ignorarlo. Almeno questo è un cattivo comportamento.
Score_Under

1
@Score_Under ancora ci sono casi in cui questo è appropriato da usare. Ad esempio, quando una funzione chiamata è supplementare, di origine / autore sconosciuti, non influisce sulla funzionalità principale, ma se gli arresti anomali potrebbero causare problemi. Mi rendo conto che sosterresti che tali chiamate dovrebbero essere adeguatamente studiate e analizzate, ma nella vita reale non è sempre possibile.
saluti il

Tuttavia, se voglio terminare il processo, uccidere -9 non dovrebbe essere l'unica opzione affidabile.
Score_Under

2

La gestione degli errori è molto importante nella programmazione. Devi mostrare all'utente cosa è andato storto. In pochissimi casi è possibile ignorare gli errori. Questa è una pessima pratica di programmazione.


2

Dal momento che non è stato ancora menzionato, è meglio usare lo stile contextlib.suppress:

with suppress(FileNotFoundError):
    os.remove('somefile.tmp')

Si noti che nell'esempio fornito, lo stato del programma rimane lo stesso, indipendentemente dall'eccezione. Vale a dire, somefile.tmpdiventa sempre inesistente.

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.