Exception Handling¶
Why Exceptions?¶
Deal:
|
def do_much(this, that):
if do_this(this) < 0:
return -1
if do_that(that) < 0:
return -1
return 0
def do_this(this):
if this == 2:
return -1
else:
return 9
def do_that(that):
if that == 5:
return -1
else:
return 'blah'
|
Exception Handling¶
Plan is: write less code ⟹ cleaner code
def do_much(this, that):
do_this(this)
do_that(that)
try:
do_much(1, 5)
except MyError as e:
print('Error:', e.msg,
file=sys.stderr)
def do_this(this):
if this == 2:
raise MyError('this is 2')
else:
return 9
def do_that(that):
if that == 5:
raise MyError('that is 5')
else:
return 'blah'
Exceptions¶
Exceptions are objects …
Python 2: can be anything
Python 3: must be derived from
class BaseException
User defined exception should be derived from
Exception
⟶ Object oriented programming
class MyError(Exception):
def __init__(self, msg):
self.msg = msg
Catching All Exceptions¶
a_dict = {}
try:
print(a_dict['novalidkey'])
except: # KeyError
print("d'oh!")
Catches everything no matter what
Hides severe programming errors
⟶ use only if you really know you want
try:
print(nonexisting_name)
except: # NameError
print("d'oh!")
Catching Exceptions By Type¶
a_dict = {}
try:
print(a_dict['novalidkey'])
except KeyError:
print("d'oh!")
NameError
(and most others) passes through… and terminate the program unless caught higher in the call chain
Very specific ⟶ best used punctually
Catching Exceptions By Multiple Types¶
a_dict = {}
try:
print(a_dict[int('aaa')])
except (KeyError, ValueError):
print("d'oh!")
(Btw, the exception list is an iterable of type objects)
As always: reflect your intentions
Is the handling the same in both cases?
I’d say very rarely
Storing the Exception’s Value¶
Many exceptions’ only information is their type
⟶ “A
KeyError
happened!”Sometimes exceptions carry additional information
class MyError(Exception):
def __init__(self, msg):
self.msg = msg
def do_something():
raise MyError('it failed')
try:
do_something()
except MyError as e:
print(e.msg)
Order of Except-Clauses (1)¶
Except-Clauses are processed top-down
⟶ Very important when exceptions are related/inherited
MyError
is aException
class MyError(Exception):
def __init__(self, msg):
self.msg = msg
def do_something():
raise MyError('it failed')
Order of Except-Clauses (2)¶
try:
do_something()
except Exception as e:
print('unexpected')
except MyError as e:
print(e.msg)
|
try:
do_something()
except MyError as e:
print(e.msg)
except Exception as e:
print('unexpected')
Rule:
|