Learning Python: Unit 8, Exceptions (original) (raw)
Why use exceptions?
♦ Error handling
♦ Event notification
♦ Special-case handling
♦ Unusual control-flows
Exception topics
♦ The basics
♦ Exception idioms
♦ Exception catching modes
♦ Class exceptions
♦ Exception gotchas
Exception basics
♦ A high-level control flow device
♦ _try_statements catch exceptions
♦ _raise_statements trigger exceptions
♦ Excep��tions are raised by Python or programs
Basic forms
● Python 2.5+: except/finally can now be mixed
● Python 2.5+: with/as context managers
● Python3.X: �except E as X�, �raise from E�
♦ try/except/else
try:
��� ������� # run/call actions
except:
��� <statements>������� # if name raised during try block
except, :
��� ������� # if 'name' raised; get extra data
else:
��� <statements>������� # if no exception was raised
♦ try/finally
try:
��� <statements>
finally:
��� <statements>������� # always run 'on the way out'
♦ raise
raise ����������� # manually trigger an exception
raise, ��� # pass extra data to catcher too
♦ assert
assert , ���
# if not test: raise AssertionError, message
♦ with/as context managers (2.5+)
# alternativeto common try/finally idioms
from __future__ import with_statement���� # till 2.6
with open('/etc/passwd', 'r') as f:������# auto-closed after with
��� for line in f:����������������������� # even if exception in block
������� print line
������� ... moreprocessing code ...
lock = threading.Lock()
with lock:������������������������������� # auto acquired, released
��� # critical section of code����������� # classes may define managers
First examples
Builtinexceptions
♦ Python triggers builtinexceptions on errors
♦ Displays message at top-level if not caught
def kaboom(list, n):
��� print list[n]�����������# trigger IndexError
try:
��� kaboom([0, 1, 2], 3)
except IndexError:����������# catch exception here
��� print 'Hello world!'����
User-defined exceptions
♦ Python (and C) programs raise exceptions too
♦ User-defined exceptions are objects
MyError= "my error"
def stuff(file):
��� raise MyError
file = open('data', 'r')���� # open a file
try:
��� stuff(file)������������� # raises exception
finally:
��� file.close()������������ # always close file
Exception idioms
♦ EOFError sometimes signals end-of-file
while1:
��� try:
������� line = raw_input()���� # read from stdin
��� except EOFError:
������� break
��� else:
������� <processnext �line� here>
♦ Searches sometimes signal success by �raise�
Found = "Item found"
def searcher():
���
try:
��� searcher()
exceptFound:
��� <success>
else:
��� <failure>
♦ Outer �try� statements can be used to debug code
try:
��� �������
except:������������� # all uncaught exceptions come here
��� import sys
��� print 'uncaught!',sys.exc_info()[:2]����# type, value
Exception catching modes
♦ Try statements nest (are stacked) at runtime
♦ Python selects first clause that matches exception
♦ Try blocks can contain a variety of clauses
♦ Multiple excepts: catch 1-of-N exceptions
♦ Try can contain �except� or �finally�, but not both
Try block clauses
Operation | Interpretation |
---|---|
except: | catch all exception types |
except name: | catch a specific exception only |
except name, value: | 2.X: catch exception and its extra data |
except name as value: | 3.X: catch exception and its instance |
except (name1, name2): | catch any of the listed exceptions |
else: | run block if no exceptions raised |
finally: | always perform block, exception or not |
��
♦ Exceptions nest at run-time
● Runs most recent matching except clause
file: nestexc.py
def action2():
��� print 1 + []����������# generate TypeError
def action1():
��� try:
������� action2()
��� except TypeError:����� # most recent matching try
������� print 'inner try'
try:
��� action1()
except TypeError:��������� # here iff action1 re-raises
��� print 'outer try'
% python nestexc.py
innertry
♦ Catching 1-of-N exceptions
● Runs first match: top-to-bottom, left-to-right
● See manuals or reference text for a complete list
try:
��� action()
except NameError:
��� ...
except IndexError
��� ...
except KeyError:
��� ...
except(AttributeError, TypeError,SyntaxError):
��� ...
else:
��� ...
♦ �finally� clause executed on the way out
● useful for �cleanup� actions: closing files,...
● block executed whether exception occurs or not
● Python propagates exception after block finishes
● but exception lost if finally runs a raise, return, or break
file: finally.py
def divide(x, y):
��� return x / y���������# divide-by-zero error?
def tester(y):
��� try:
������� printdivide(8, y)
��� finally:
������� print 'on the way out...'
print'\nTest 1:'; tester(2)
print'\nTest 2:'; tester(0)���� # trigger error
% python finally.py
Test 1:
4
onthe way out...
Test 2:
onthe way out...
Traceback(innermost last):
� File "finally.py", line 11, in ?
��� print 'Test 2:'; tester(0)
� File "finally.py", line 6, in tester
��� print divide(8, y)
� File "finally.py", line 2, in divide
��� return x / y��������� # divide-by-zero error?
ZeroDivisionError: integer division or modulo
♦ Optional data
● Provides extra exception details
● Python passes None if no explicit data
file: helloexc.py
myException = 'Error'���� # string object
def raiser1():
��� raise myException, "hello"���� # raise, pass data
def raiser2():
��� raise myException�������������# raise, None implied
def tryer(func):
��� try:
������� func()
��� except myException, extraInfo:
����� ��print 'got this:', extraInfo
% python
>>> from helloexc import *
>>> tryer(raiser1)
gotthis: hello
>>> tryer(raiser2)
gotthis: None
Class exceptions
● Should use classes today: only option in 3.X, per BDFL
● Useful for catching categories of exceptions
● String exception match: same object (�is� identity)
● Class exception match: named class or subclass of it
● Class exceptions support exception hierarchies
General raise forms
raisestring����������� # matches same string object
raisestring, data �����# optional extra data (default=None)
raiseclass, instance�� # matches class or its superclass
raiseinstance��������� # = instance.__class__, instance
Example
file: classexc.py
classSuper:����� pass
classSub(Super): pass
def raiser1():
��� X = Super()���������� # raise listed class instance
��� raise X
def raiser2():
��� X = Sub()������������ # raise instance of subclass
��� raise X
for func in (raiser1, raiser2):
��� try:
������� func()
��� except Super:���������������# match Super or a subclass
������� import sys
������� print'caught:', sys.exc_info()[0]
% python classexc.py
caught: <class Super at 770580>
caught: <class Sub at 7707f0>
Example: numeric library
class NumErr: pass
class Divzero(NumErr): pass
class Oflow(NumErr): pass
raise DivZero()
import mathlib
try:
��� mathlib.func(�)
except mathlib.NumErr:
��� �report and recover�
Example: using raised instance
class MyBad:
��� def__init__(self, file, line):
������� self.file = file
������� self.line = line
��� defdisplay(self):
������� print self.file * 2
def parser():
��� raise MyBad('spam.txt', 5)
try:
��� parser()
except MyBad, X:
��� print X.file, X.line
��� X.display()
# built-infile error numbers
def parser():
��� open('nonesuch')
try:
��� parser()
except IOError, X:
��� print X.errno, '=>', X.strerror
Exception gotchas
What to wrap in a try statement?
● Things that commonly fail: files, sockets, etc.
● Calls to large functions, not code inside the function
● Anything that shouldn�t kill your script
● Simple top-level scripts often should die on errors
● See also atexit module for shutdown time actions
Catching too much?
● Empty except clauses catch everything
● But may intercept error expected elsewhere
try:
��� [...]
except:
��� [...]��# everythingcomes here: even sys.exit()!
Catching too little?
● Specific except clauses only catch listed exceptions
● But need to be updated if add new exceptions later
● Class exceptions would help here: category name
try:
��� [...]
except (myerror1, myerror2):�� # what if I add a myerror3?
��� [...]� # non-errors
else:
��� [...]� # assumed to be an error
Solution: exception protocol design
Lab Session 7
Click here to go to lab exercises
Click here to go to exercise solutions