Reputation: 99526
From Python in a Nutshell
A try / except / finally statement, such as:
try: ...guarded clause... except ...expression...: ...exception handler code... finally: ...clean-up code...
is equivalent to the nested statement:
try: try: ...guarded clause... except ...expression...: ...exception handler code... finally: ...clean-up code...
Can it be written equivalent to a form without finally
?
Is it equivalent to
try:
...guarded clause...
except ...expression...:
...exception handler code...
...clean-up code...
...clean-up code...
Thanks.
Upvotes: 1
Views: 1710
Reputation: 13823
Here's what I use to avoid creating a function for the finally
code and having to call it from two different places.
try:
pass
pass
1/0
pass
pass
pass
raise Exception('Success')
except Exception, e:
if e.message != 'Success':
import traceback
print traceback.format_exc()
print 'in finally'
print 'in finally'
print 'in finally'
if e.message != 'Success':
raise
Output on Linux:
Traceback (most recent call last):
File "./test_finally.py", line 34, in <module>
1/0
ZeroDivisionError: integer division or modulo by zero
in finally
in finally
in finally
Traceback (most recent call last):
File "./test_finally.py", line 34, in <module>
1/0
ZeroDivisionError: integer division or modulo by zero
shell returned 1
Upvotes: 0
Reputation: 281643
Yes, but not the way you did it.
try:
do_stuff()
except OneProblem:
handle_it()
except DifferentProblem:
handle_that()
finally:
cleanup()
is equivalent to
try:
try:
do_stuff()
except OneProblem:
handle_it()
except DifferentProblem:
handle_that()
except:
# Clean up if an unhandled exception happened, then restore the exception.
cleanup()
raise
# Also clean up if we're not propagating an exception.
cleanup()
in terms of cleanup always happening and never happening twice, though things like exception chaining and tracebacks might behave differently.
Upvotes: 1
Reputation: 104772
No, your alternative code is not quite equivalent to the try
/except
/finally
version. To understand why, think about what would happen if a second exception was triggered inside the ...exception handler code...
part of your example.
Here's a demo that shows the issue:
try:
print('in try') # guarded code
1/0 # oops, a bug
except ZeroDivisionError:
print('top of except') # exception handling code
name_does_not_exist # oops, the exception handling code is buggy too
print('end of except') # this is a bad place for cleanup code
finally:
print('in finally') # this is a much better place to do cleanup
Output:
in try
top of except
in finally
Traceback (most recent call last):
File "<ipython-input-17-63590fc64963>", line 6, in <module>
name_does_not_exist # oops, the exception handling code is buggy too
NameError: name 'name_does_not_exist' is not defined
Note that the end of except
message never gets printed, since the NameError
occurs on the previous line. If line was the critical cleanup code, a program with only try
and except
would fail to run it. If you put the cleanup code in a finally
block though, it's guaranteed to run regardless of any exceptions raised in any other part of the code.
Upvotes: 1