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

Click here to go to solution source files

Click here to go to lecture example files