2012-07-18 12 views
134

io non sono sicuro perché abbiamo bisogno finally in try...except...finally dichiarazioni. A mio parere, questo blocco di codicePerché abbiamo bisogno della clausola "finally" in Python?

try: 
    run_code1() 
except TypeError: 
    run_code2() 
other_code() 

è lo stesso con questo usando finally:

try: 
    run_code1() 
except TypeError: 
    run_code2() 
finally: 
    other_code() 

mi sto perdendo qualcosa?

risposta

191

fa una differenza se si torna presto:

try: 
    run_code1() 
except TypeError: 
    run_code2() 
    return None # The finally block is run before the method returns 
finally: 
    other_code() 

paragonabile a questo:

try: 
    run_code1() 
except TypeError: 
    run_code2() 
    return None 

other_code() # This doesn't get run if there's an exception. 

Altre situazioni che possono causare differenze:

  • Se viene generata un'eccezione all'interno il blocco eccetto.
  • Se viene generata un'eccezione in run_code1() ma non è un TypeError.
  • Altre dichiarazioni di controllo del flusso, come continue e break dichiarazioni.
+0

prova: #x = Ciao + 20 x = 10 + 20 eccezione: print 'Sono in salvo blocco' x = 20 + 30 altro: print 'Sono in blocco else' x + = 1 infine: stampa 'Finalmente x =% s'% (x) –

11

non sono equivalenti. Infine, il codice viene eseguito indipendentemente da ciò che accade. È utile per il codice di pulizia che deve essere eseguito.

+6

'Finalmente il codice viene eseguito indipendentemente da ciò che accade ... a meno che non ci sia un ciclo infinito. O un powercut. O 'os._exit()'. Oppure ... –

+2

... un segfault. O 'SIGABRT'. –

+2

@Mark In realtà, sys.exit genera un'eccezione normale. Ma sì, qualsiasi cosa che faccia immediatamente terminare il processo significherà che nient'altro viene eseguito. – Antimony

7

I blocchi di codice non sono equivalenti. La clausola finally verrà eseguita anche se run_code1() genera un'eccezione diversa da TypeError o se run_code2() genera un'eccezione, mentre la other_code() nella prima versione non verrà eseguita in questi casi.

6

Nel tuo primo esempio, cosa succede se run_code1() genera un'eccezione che non è TypeError? ... other_code() non verrà eseguito.

Confrontare che con la versione finally:: other_code() è garantita l'esecuzione indipendentemente dall'eventuale eccezione generata.

35

È possibile utilizzare finally per assicurarsi che i file o le risorse siano chiusi o rilasciati indipendentemente dal fatto che si verifichi un'eccezione, anche se non si rileva l'eccezione. (O se non si cattura che specifica eccezione.)

myfile = open("test.txt", "w") 

try: 
    myfile.write("the Answer is: ") 
    myfile.write(42) # raises TypeError, which will be propagated to caller 
finally: 
    myfile.close()  # will be executed before TypeError is propagated 

In questo esempio si sarebbe meglio utilizzando l'istruzione with, ma questo tipo di struttura può essere utilizzato per altri tipi di risorse .

Alcuni anni più tardi, ho scritto a blog post su un abuso di finally che i lettori possono trovare divertenti.

3

finally è la definizione di "pulizia azioni". La clausola finally viene eseguita in ogni caso prima di lasciare l'istruzione try, a prescindere che si sia verificata o meno un'eccezione (anche se non la si gestisce).

I secondo esempio di Byers.

2

Infine può essere utilizzato anche quando si desidera eseguire codice "opzionale" prima di eseguire il codice per il proprio lavoro principale e che il codice opzionale potrebbe non riuscire per vari motivi.

Nell'esempio seguente, non sappiamo con precisione quale tipo di eccezioni può generare store_some_debug_info.

Potremmo correre:

try: 
    store_some_debug_info() 
except Exception: 
    pass 
do_something_really_important() 

Ma, la maggior parte dei linters si lamenta perché la cattura troppo vaga di un'eccezione. Inoltre, dal momento che stiamo scegliendo solo gli errori pass, il blocco except in realtà non aggiunge valore.

try: 
    store_some_debug_info() 
finally: 
    do_something_really_important()  

Il codice sopra riportato ha lo stesso effetto del primo blocco di codice ma è più conciso.

1

perfetto esempio è il seguente:

try: 
    #x = Hello + 20 
    x = 10 + 20 
except: 
    print 'I am in except block' 
    x = 20 + 30 
else: 
    print 'I am in else block' 
    x += 1 
finally: 
    print 'Finally x = %s' %(x) 
1

Come illustrato nella documentation, la clausola finally destinato a definire azioni di pulizia che devono essere eseguite in tutte le circostanze.

Se finally è presente, specifica un gestore di 'pulizia'. Viene applicata la clausola try , incluse le clausole except e else. Se si verifica un'eccezione in una qualsiasi delle clausole e non viene gestita, l'eccezione viene temporaneamente salvata. La clausola finally viene eseguita. Se esiste un'eccezione salvata, viene sollevata di nuovo alla fine della clausola finally .

Un esempio:

>>> def divide(x, y): 
...  try: 
...   result = x/y 
...  except ZeroDivisionError: 
...   print("division by zero!") 
...  else: 
...   print("result is", result) 
...  finally: 
...   print("executing finally clause") 
... 
>>> divide(2, 1) 
result is 2.0 
executing finally clause 
>>> divide(2, 0) 
division by zero! 
executing finally clause 
>>> divide("2", "1") 
executing finally clause 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in divide 
TypeError: unsupported operand type(s) for /: 'str' and 'str' 

Come si può vedere, la clausola finally viene eseguita in ogni caso. Il numero TypeError generato dividendo due stringhe non è gestito dalla clausola except e pertanto controrilanciato dopo che è stata eseguita la clausola finally.

Nelle applicazioni del mondo reale, la clausola finally è utile per il rilascio di risorse esterne (come file o connessioni di rete), indipendentemente dal fatto che l'utilizzo della risorsa abbia avuto successo.

1

Per aggiungere alle altre risposte di cui sopra, la clausola finally viene eseguita indipendentemente da ciò, mentre la clausola else viene eseguita solo se non è stata sollevata un'eccezione.

Per esempio, la scrittura su un file senza eccezioni sarà uscita la seguente:

file = open('test.txt', 'w') 

try: 
    file.write("Testing.") 
    print("Writing to file.") 
except IOError: 
    print("Could not write to file.") 
else: 
    print("Write successful.") 
finally: 
    file.close() 
    print("File closed.") 

USCITA:

Writing to file. 
Write successful. 
File closed. 

Se v'è un'eccezione, il il codice mostrerà quanto segue, (nota che un errore intenzionale è causato mantenendo il file re Ad-solo.

file = open('test.txt', 'r') 

try: 
    file.write("Testing.") 
    print("Writing to file.") 
except IOError: 
    print("Could not write to file.") 
else: 
    print("Write successful.") 
finally: 
    file.close() 
    print("File closed.") 

USCITA:

Could not write to file. 
File closed. 

Possiamo vedere che la clausola finally esegue indipendentemente un'eccezione. Spero che questo ti aiuti.

Problemi correlati