Edit: in retrospect, this is not a well thought-out question, but I'm leaving it here for future readers who may have the same misunderstanding as me.
There may be a lapse in my understanding of how try/except/finally work in Python, but I would expect the following to work as described in comments.
from sys import argv
try:
x = argv[1] # Set x to the first argument if one is passed
finally:
x = 'default' # If no argument is passed (throwing an exception above) set x to 'default'
print(x)
I would expect that the file above (foo.py) should print default
when run as python .\foo.py
and would print bar
if run as python .\foo.py bar
.
The bar
functionality works as expected, however, the default
behaviour does not work; if I run python .\foo.py
, I get an IndexError:
Traceback (most recent call last):
File ".\foo.py", line 4, in <module>
x = argv[1]
IndexError: list index out of range
As a result, I have two questions:
except
clause?This is expected behaviour. try:..finally:...
alone doesn't catch exceptions. Only the except
clause of a try:...except:...
does.
try:...finally:...
only guarantees that the statements under finally
are always executed, whatever happens in the try
section, whether the block succeeds or is exited because of a break
, continue
, return
or an exception. So try:...finally:...
is great for cleaning up resources; you get to run code no matter what happens in the block (but note that the with
statement and context managers let you encapsulate cleanup behaviour too). If you want to see examples, then the Python standard library has hundreds.
If you need to handle an IndexError
exception in a try
block, then you must use an except
clause. You can still use a finally
clause as well, it'll be called after the except
suite has run.
And if you ever get to work with much older Python code, you'll see that in code that must run with Python 2.4 or older try:....finally:...
and try:...except:...
are never used together. That's because only as of Python 2.5 have the two forms been unified.