Ricerca…


Overzealous tranne clausola

Le eccezioni sono potenti, ma una singola clausola eccessivamente zelante può portare via tutto in un'unica riga.

try:
    res = get_result()
    res = res[0]
    log('got result: %r' % res)
except:
    if not res:
        res = ''
    print('got exception')

Questo esempio dimostra 3 sintomi dell'antiPattern:

  1. L' except con nessun tipo di eccezione (riga 5) otterrà eccezioni anche salutari, incluso KeyboardInterrupt . Ciò impedirà al programma di uscire in alcuni casi.
  2. Il blocco except non genera un errore, il che significa che non saremo in grado di stabilire se l'eccezione proviene da get_result o perché res era una lista vuota.
  3. Peggio ancora, se eravamo preoccupati che il risultato fosse vuoto, abbiamo causato qualcosa di molto peggio. Se get_result fallisce, res rimarrà completamente disinserito, e il riferimento a res nel blocco except, solleverà NameError , mascherando completamente l'errore originale.

Pensa sempre al tipo di eccezione che stai cercando di gestire. Dai una lettura alla pagina delle eccezioni e fatti un'idea delle eccezioni di base esistenti.

Ecco una versione fissa dell'esempio sopra:

import traceback

try:
    res = get_result()
except Exception: 
    log_exception(traceback.format_exc())
    raise
try:
    res = res[0]
except IndexError:
    res = ''

log('got result: %r' % res)

Rileviamo eccezioni più specifiche, controrilanciare ove necessario. Qualche altra riga, ma infinitamente più corretta.

Guardando prima di saltare con la funzione intensiva del processore

Un programma può facilmente perdere tempo chiamando più volte una funzione intensiva del processore.

Ad esempio, prendi una funzione che assomiglia a questa: restituisce un intero se il value input può produrne uno, altrimenti None :

def intensive_f(value): # int -> Optional[int]
   # complex, and time-consuming code
   if process_has_failed:
       return None
   return integer_output

E potrebbe essere usato nel modo seguente:

x = 5
if intensive_f(x) is not None:
    print(intensive_f(x) / 2)
else:
    print(x, "could not be processed")

print(x)

Mentre questo funzionerà, ha il problema di chiamare intensive_f , che raddoppia il tempo di esecuzione del codice. Una soluzione migliore sarebbe ottenere in anticipo il valore di ritorno della funzione.

x = 5
result = intensive_f(x)
if result is not None:
    print(result / 2)
else:
    print(x, "could not be processed")

Tuttavia, un modo più chiaro e possibilmente più pitoni è usare le eccezioni, ad esempio:

x = 5
try:
    print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
    print(x, "could not be processed")

Qui non è necessaria alcuna variabile temporanea. Spesso può essere preferibile utilizzare una dichiarazione assert e catturare l' AssertionError .

Chiavi del dizionario

Un esempio comune di dove questo può essere trovato è l'accesso alle chiavi del dizionario. Ad esempio confronta:

bird_speeds = get_very_long_dictionary()

if "european swallow" in bird_speeds:
    speed = bird_speeds["european swallow"]
else:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

con:

bird_speeds = get_very_long_dictionary()

try:
    speed = bird_speeds["european swallow"]
except KeyError:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

Il primo esempio deve esaminare il dizionario due volte e, poiché questo è un dizionario lungo, potrebbe richiedere molto tempo per farlo ogni volta. Il secondo richiede solo una ricerca attraverso il dizionario, risparmiando così molto tempo del processore.

Un'alternativa a questo è usare dict.get(key, default) , tuttavia molte circostanze potrebbero richiedere operazioni più complesse da eseguire nel caso in cui la chiave non sia presente



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow