CS 112 Intro to Programming Exceptions
description
Transcript of CS 112 Intro to Programming Exceptions
CS 112Intro to Programming
Exceptions
George Mason University
Exception Handling: Basic Syntax
try:#watch for exceptions
heretry_suite
except:#exception handling codeexcept_suite
2
A piece of code that is potential to crash in
runtime
Exceptions Hierarchy
BaseException +-- KeyboardInterrupt +-- Exception +-- ArithmeticError | +-- ZeroDivisionError +-- EnvironmentError | +-- IOError +-- EOFError +-- LookupError | +-- IndexError | +-- KeyError +-- NameError +-- SyntaxError +-- SystemError +-- TypeError +-- ValueError
• There are many exception classes organized into a hierarchy→ using inheritance (parent and child class relationships)
(found at http://docs.python.org/3.2/library/exceptions.html )Whenever a runtime error occur in ‘try’, the ‘except’ will handle this
specific exception (event)
Validating Input
e4.pyneed_input = Truewhile need_input: x = eval(input("#: ")) need_input = False
print ("successfully got x: "+str(x))
Loop continues to execute, raising and handling exceptions, until user
complies.
Validating Input
e4.pyneed_input = Truewhile need_input: try: x = eval(input("#: ")) need_input = False except Exception as e: print(e)print ("successfully got x: "+str(x))
Loop continues to execute, raising and handling exceptions, until user
complies.demo$ python3 e4.py#: 5successfully got x: 5#: asdfname 'asdf' is not defined#: 3/0division by zero
Exception1
Exception2
Exception HandlingThere are three basic choices when handling exceptions:
•handle it •defer it up the calling chain •do both: handle it, but also defer it to the caller.
Example:•if method A calls method B, and then B calls method C, and C raises an exception:
• C can handle it• C can defer it to B (the caller of C)
→ B, and in turn, A, then have the same choices• C can handle it and then re-raise it
6
Exception Handling
7
Method A(Function A)
Method B
Method C
Exception(error)
I will handle it
Propagate(report the error)
Validating Input
e4.pyneed_input = Truewhile need_input: try: x = eval(input("#: ")) need_input = False except Exception as e: print(e)print ("successfully got x: "+str(x))
Loop continues to execute, raising and handling exceptions, until user
complies.demo$ python3 e4.py#: 5successfully got x: 5#: asdfname 'asdf' is not defined#: 3/0division by zero
Exception1
Exception2
Exception Handling
9
Method A
Method B
Method C
Exception
Ouch!
defer
I will handle it
Deferring Exceptions
10
e12.pydef buggy (): x = int(input("#? ")) return 5/xdef main(): try: print(buggy()) except ZeroDivisionError as e: print("sadly, we cannot do zero division.")main()
demo$ python3 e12.py #? 100.5demo$ python3 e12.py #? 0sadly, we cannot do zero division.demo$ python3 e12.py #? asdfTraceback … ValueError…
• exception raised in buggy crashes (propagates) out to whatever called it: main, in this case.
• main catches the exception.
Exception Handling
11
Method A
Method B
Method C
Exception
Ouch!
defer
I will handle itPropagate
(report the error)
Exception Handling
12
Method A
Method B
Method C
Exception
I will handle some
Defer the rest
I will handle some
Defer the rest
Deferring Some Exceptions
13
e13.pydef buggy (): try: x = int(eval(input("#? "))) return 5/x except ValueError as e: print ("didn't get an int!") return 0def main(): try: print(buggy()) except ZeroDivisionError as zde: print("sadly, we cannot do zero division.")main()
demo$ python3 e13.py#? 31.6666666666666667demo$ python3 e13.py#? "hello"didn't get an int!0demo$ python3 e13.py#? 0sadly, we cannot do zero division.demo$ #? (1,2,3)Traceback … TypeError…
• ValueErrors caught in buggy.• ZeroDivisionErrors propagated to main, caught there.• TypeErrors propagated all the way, crashing entire
program.
Deferring - another example
14
e14.pydef find(): try: d = {1:'a',2:'b',3:'c'} v = int(input("#? ")) return d[6/v] except KeyError as verr: return "red herring"def main(): try: print(find()) except ZeroDivisionError as zde: print("sadly, we cannot do zero division.")main()
demo$ python3 e14.py#? 6ademo$ python3 e14.py#? 4red herringdemo$ python3 e14.py#? 0 sadly, we cannot do zero division.demo$ python3 e14.py#? asdfTraceback…ValueError…
• KeyError handled in find()• ZeroDivisionError deferred in find(), then handled in main()• ValueErrors unhandled.
Exception Handling
15
Method A
Method B
Method C
Exception
I will handle some
Defer the rest
I will handle some
Defer the rest
If the exception is handled by C, then B
will not notice it
Verify the password
Count failed times
Login bank account
Exception Handling
16
Method A
Method B
Method C
Exception
I will handle it
Re-raise
I will handle it, too
Verify the password
Count failed times
Login bank account
After the exception is handled by C, we will manually inform B
Raising Exceptions• We can generate an exception on purpose
(and hopefully catch it somewhere else!)• done with a raise statement, which needs an
expression of some Exception type. This usually means calling a constructor (__init__). Examples:• raise Exception("boo!")
raise ArithmeticError ("this doesn't add up!")raise ValueError("needed a positive number")
• except IOError as e: print ("catching it, re-raising it.") raise e
Exceptions Hierarchy
BaseException +-- KeyboardInterrupt +-- Exception +-- ArithmeticError | +-- ZeroDivisionError +-- EnvironmentError | +-- IOError +-- EOFError +-- LookupError | +-- IndexError | +-- KeyError +-- NameError +-- SyntaxError +-- SystemError +-- TypeError +-- ValueError
• There are many exception classes organized into a hierarchy→ using inheritance (parent and child class relationships)
(found at http://docs.python.org/3.2/library/exceptions.html )Build-in exception, everyone know what
they means
Raising ExceptionsReusing/raising a few specific exception types is useful:• Exception for general issues (but a bit vague)• TypeError, when the supplied arg. was the
wrong type• ValueError when your code only should be run
on some batch of values and the wrong one was given
• Any of them can be reused if it suits your purpose, just call their constructor (see examples on previous slide)
Then you can raise them and catch them as before.→ but you can also make brand new types of exceptions!
Re-raising the Same Exception
20
We can directly re-raise the caught exception object.• To force this exception propagate, since by default
exception only get handled once• No need to construct an exception value-we already
have an exception object.e15.pydef get_input(): try: return float(eval(input("#: "))) except ValueError as e: print("in get_input: "+str(e)) raise edef main(): try: print( get_input()) except (TypeError, ValueError) as e: print ("in main: "+str(e))main()
demo$ python3 e16.py#: 'a'in get_input: could not convert string to float: 'a'in main: could not convert string to float: 'a'
note the quotes!
Re-raising Another Exceptions
21
• Initialize an exception ourselves• We want to customized the error
information to the caller
e15.pydef get_input(): try: return float(eval(input("#: "))) except ValueError as e: print("in get_input: "+str(e)) raise (ValueError("ERR"))def main(): try: print( get_input()) except (TypeError, ValueError) as e: print ("in main: "+str(e))main()
demo$ python3 e15.py #: 'asdf'in get_input: could not convert string to float: 'asdf'in main: ERRdemo$ python3 e15.py #: (1,2,3)in main: float() argument must be a string or a numberdemo$ python3 e15.py #: asdfTraceback…NameError…
note the quotes!
Exception Handling
22
Method A
Method B
Method C
Exception
I will handle it
Re-raise
I will handle it, too
Verify the password
Count failed times
Login bank account
After the exception is handled by C, we will manually inform B
Did you find initialization of an exception looks the same as initialization of an object of a class?Actually exceptions are just a kind of class:
Exceptions and Classes
e15.pydef get_input(): try: return float(eval(input("#: "))) except ValueError as e: print("in get_input: "+str(e)) raise (ValueError("ERR"))def main(): try: print( get_input()) except (TypeError, ValueError) as e: print ("in main: "+str(e))main()
Class (web page) Exception
Driven by user behavior
Driven by runtime error
Click a link or button
Through out an exception
Open a new web page
Initialize an exception object
Exceptions Hierarchy
BaseException +-- KeyboardInterrupt +-- Exception +-- ArithmeticError | +-- ZeroDivisionError +-- EnvironmentError | +-- IOError +-- EOFError +-- LookupError | +-- IndexError | +-- KeyError +-- NameError +-- SyntaxError +-- SystemError +-- TypeError +-- ValueError
• There are many exception classes organized into a hierarchy→ using inheritance (parent and child class relationships)
(found at http://docs.python.org/3.2/library/exceptions.html )Inheritance relations
We usually define customized exception
as child class of build-in ones
User-Defined ExceptionsWe can create our own types of exceptions.They can be raised, propagated, and caught just like any other exception types.
25
e10.pyclass Disallowed (Exception): def __init__(self, value): self.value = value
26
e11.pyfrom e10 import Disallowedtry: x = int(input("#? ")) if x==13: raise Disallowed("that's unlucky!") print(x*10)except Disallowed as dis: print("uhoh: "+dis.value)except Exception as e: print(e)
demo$ python3 e11.py#? 550demo$ python3 e11.py#? 13uhoh: that's unlucky!demo$ python3 e11.py#? asdfinvalid literal for int() with base 10: 'asdf'
• raise keyword used with a call to our exception's constructor
• except-block used with our new type of exception
User-Defined Exceptions
Raise an exception just like:
If want to trigger this event, then raise this exception
• A class can use exceptions within its methods, just like we've done before.
e17.pyclass LongNameException(Exception): def __init__(self, text="too long!"): self.text = text
class Artist(object): def __init__(self, name="None"): self.__name = name def set_name (self, name): try: if (len(name))>10: raise LongNameException() else: self.__name = name except LongNameException as e: print(e.text)
Example: using exception handling in
classes
demo$ python3 -i e17.py>>> alice = Artist()>>> alice.set_name("Alice Cooper")too long!
e18.pyclass LongNameException(Exception): def __init__(self, text="too long!", data=""): self.text = text self.data = data
class Artist(object): def __init__(self, name="None"): self.__name = name def set_name (self, name): try: if (len(name))>10: raise LongNameException(data=(len(name))) else: self.__name = name except LongNameException as e: print(e.text+" ("+str(e.data)+")")
Example: using instance variables in exceptions
demo$ python3 -i e18.py>>> alice = Artist()>>> alice.set_name("Alice Cooper")too long! (12)
Our exceptions are objects, and they can
have/use instance variables like data.