Le eccezioni dovrebbero essere sollevate più in alto o più in basso o entrambe? [chiuso]

4

Quando si chiama una funzione in un'applicazione Python, la funzione spesso chiamate funzioni più in basso che ancora una volta chiamare le funzioni più in basso, ecc E 'facile passare unknowlingly un cattivo valore di funzione di primo livello che provoca un guasto più in basso . Naturalmente, i parametri dovrebbero essere controllati e le eccezioni sollevate con messaggi di errore utili. Ma dove dovrebbe essere questo idealmente fatto, e perché?

  1. Il più in alto possibile (i messaggi di errore sono probabilmente più facili da capire poiché sono più vicini all'utente)
  2. Per quanto in basso possibile (messaggi di eccezione sono più vicini al punto in cui sarebbe in realtà si verificano gli errori, e le verifiche possono essere più semplice dal momento che probabilmente non dipendono da qualche oscura combinazione di valori di ingresso, ma i messaggi ei nomi delle variabili potrebbero essere così lontano da parte dell'utente che l'unico modo per sapere che cosa effettivamente deve essere cambiato nella chiamata di livello superiore è quello di ispezionare l'origine dall'alto verso il basso)
  3. Entrambi
posta cmeeren 02.10.2015 - 09:34
fonte

4 risposte

5

Genera un'eccezione nel momento in cui sai che il tuo codice non sarà in grado di ripristinare da una condizione di errore (senza l'intervento dell'utente).

Esempio: il tuo codice determina che un percorso fornito a un file su disco non esiste e che il codice non può procedere senza un buon percorso. Getta in quel momento, ovunque si verifichi nel tuo codice.

Includere sempre nel messaggio di errore informazioni sufficienti per diagnosticare il problema. Mantieni lo stack delle chiamate; ne avrai bisogno per tornare al punto nel codice in cui è stata generata l'eccezione. Lo stack di chiamate ti dirà non solo dove è avvenuto il lancio, ma ogni chiamata di funzione o metodo che ha avuto luogo fino al momento del lancio.

L'intero punto di gestione delle eccezioni è di fornire la possibilità di generare un'eccezione ovunque si verifichi una condizione di errore irreversibile.

    
risposta data 02.10.2015 - 09:36
fonte
1

Python ha 2 stili di codifica:

  1. Più facile chiedere perdono che permesso (EAFP) : questo stile di codifica si basa su testa a testa e prova . Quindi usi un sacco di blocchi try-except invece di istruzioni if

    try:
        ham = spam.eggs
    except AttributeError:
        handle_error()
    
  2. Guarda prima di saltare (LBYL) : questo metodo è preferito in linguaggi come C e Java .

    if hasattr(spam, 'eggs'):
        ham = spam.eggs
    else:
        handle_error() 
    

    Questo non è il modo Pythonic per alcuni sviluppatori e la documentazione spiega alcuni punti chiave:

    In a multi-threaded environment, the LBYL approach can risk introducing a race condition between “the looking” and “the leaping”. For example, the code, if key in mapping: return mapping[key] can fail if another thread removes key from mapping after the test, but before the lookup. This issue can be solved with locks or by using the EAFP approach.

    Il linguaggio Java è il contrasto di Python in questo modo

    (In Java) The moral of this story is simple:exceptions are, as their name impllies, to be used only for exceptional conditions; they should never be used for ordinary control flow.

Questa risposta ha una buona dimostrazione su quando utilizzare EAFP e quando non .

Se stai usando Python, è normale usare l'eccezione al posto di if-conditions e gestire la situazione in base all'eccezione che si cattura. Questo ti farà usare un'eccezione a ogni livello del codice. In questo modo sarai indirizzato alla risposta 3 o all'opzione 4) a qualsiasi livello che puoi utilizzare . Se il tempo di esecuzione è molto importante, puoi controllare sopra la domanda SO .

    
risposta data 02.10.2015 - 11:04
fonte
0

La risposta breve è "Entrambi".
potresti voler intercettare "errori" nella fase iniziale, lanciando fuori dati cattivi (anche se è discutibile se si tratti di una "eccezione"). sicuramente vuoi gettare un'eccezione quando le cose vanno "male male", e che tende ad essere più in basso negli strati di codice.

Una domanda da considerare prima di lanciare un'eccezione - "Allora cosa?" Se il tuo codice genera un'eccezione, qual è il codice di qualcun altro che sta per fare su di esso?

Questo è il motivo per cui ci sono molte classi di eccezioni, piuttosto che un semplice oggetto "Errore" a cui è associato un errore [arbitrario] "Numero" associato.
Se un pezzo di codice può intercettare la tua eccezione, analizzare che cosa è andato storto (forse da ciò che è passato in l'eccezione) e poi recuperare da quella situazione, tutto senza che l'Utente sapesse che qualcosa è successo, quindi sei arrivato ad un Vincitore. Utilizzare classi di eccezioni specifiche che possono essere catturate e gestite separatamente.

Se tutto ciò che si vuole fare è scaricare l'eccezione in un file di registro ( mai mostrare tutto sullo schermo!), quindi riutilizzare le classi di eccezione di base fornite è probabilmente tutto ciò che si ' Ne avrò mai bisogno.

    
risposta data 02.10.2015 - 14:12
fonte
-2

La risposta è "3. Entrambe." Ogni livello offre un'interfaccia specifica e questa interfaccia presenta vincoli specifici. Questi vincoli dovrebbero essere sempre applicati mediante la convalida. Uno strato non dovrebbe eseguire la convalida di un altro livello, né fare affidamento su un altro livello per eseguirne la convalida. Se sposti un livello in un sistema diverso, dovrebbe comunque essere in grado di funzionare.

Tutte le eccezioni inattese (eccezioni su cose che normalmente non dovrebbero accadere) indicano un bug nel codice che ha generato l'eccezione, eccetto "InvalidArgumentException", che indica un bug nel codice che ha chiamato il codice che ha generato l'eccezione.

Quindi, se il livello A richiama il livello B, e il livello A contiene un bug che fa passare informazioni errate al livello B, ma il livello B non esegue la propria convalida, il livello B genera qualche eccezione "FailedToDoWhatYouAskedMeToDo", a A quel punto inizierai naturalmente a cercare il bug nel livello B. Se il livello B esegue la propria convalida, il livello B genererà invece una "InvalidArgumentException", quindi ti indicherà di cercare il bug nel livello A.

Quindi, se non disponi di ogni livello per la propria convalida, sarai costantemente confuso su dove si trova un bug. Avrai spesso un livello che genera un'eccezione per un bug che esiste in un altro livello, che è un altro modo per dire che potresti avere un bug da qualche parte e aspettarti che un livello diverso lo trovi. Questo è il caos, e deve essere evitato a tutti i costi.

C'è un punto sottile che forse vale la pena menzionare nel caso di Python, perché per quanto ne so, Python è un po 'scomodo rispetto alla distinzione tra pubblico e privato. Normalmente, è possibile evitare la duplicazione della convalida all'interno di un livello specifico, avendo solo funzioni pubbliche di convalida. In altre parole, non è necessario che le funzioni private di un livello ripetano la convalida che è già stata eseguita da funzioni pubbliche. Ma se tutte le funzioni sono pubbliche, devono essere convalidate tutte.

    
risposta data 02.10.2015 - 10:03
fonte

Leggi altre domande sui tag