Errors that occur during runtime are called exceptions.
What are some exceptions that we've seen? That is, what errors have occurred during runtime?
Traceback (most recent call last):
File "/tmp/exceptions.py", line 1, in <module>
5 / 0
ZeroDivisionError: integer division or modulo by zero
Traceback (most recent call last):
File "/tmp/exceptions.py", line 1, in <module>
int("foo")
ValueError: invalid literal for int() with base 10: 'foo'
Traceback (most recent call last):
File "/tmp/exceptions.py", line 2, in <module>
print(a[3])
IndexError: list index out of range
Traceback (most recent call last):
File "/tmp/exceptions.py", line 1, in <module>
"foo" + 5
TypeError: cannot concatenate 'str' and 'int' objects
Traceback (most recent call last):
File "/tmp/exceptions.py", line 1, in <module>
"foo" + 5
TypeError: cannot concatenate 'str' and 'int' objects
We see the following details:
A list of all exception types can be found at: http://docs.python.org/3.2/library/exceptions.html
The base exception is just Exception, but there are specific ones after that. From the previous slides, and our past experience programming, some exceptions we've seen include:
The root Exception, and the other exception types that follow from it is called an exception hierarchy
We can gracefully recover from exceptions!
For example, a common source of runtime errors is user input…
Let's write a simple interactive program that converts inches to feet:
inches = input("inches\n>")
print(float(inches)/12)
Let's try running the program…
Everything works fine until? Is there a certain kind of input that will cause an error in this program?
inches
>asdf
Traceback (most recent call last):
File "foo.py", line 2, in <module>
print(float(inches)/23)
ValueError: invalid literal for int() with base 10: 'asdf'
…Maybe! Let's try a couple of things. →
How about isdigit and isnumeric?
s = 'asdf'
print(s.isdigit())
print(s.isnumeric())
But they don't let legitimate input through!
s = '3.2'
print(s.isdigit())
print(s.isnumeric())
Any other ways to allow strings like 3.2 in, but still prevent strings that are not composed numbers and a decimal point? →
Sometimes it's…
Easier to Ask Forgiveness than Permission
There's a construct in most programming languages that lets you handle exceptions. In python, that construct is a try-except block. It's similar to an if-else:
try:
# stuff that I want to do
except:
# stuff to do if an error occurs
What is the output of this code?
a = [1, 2, 3]
try:
print(a[100])
except:
print("sorry, try another!")
sorry, try another!
What is the output of this code?
a = [1, 2, 3]
try:
print(a[0])
except:
print("sorry, try another!")
1
Let's modify our program so that it behaves in a similar way, but uses try-except instead of testing with an if statement first.
inches = input("inches\n>")
print(float(inches)/12)
inches = input("inches\n>")
try:
print(float(inches)/12)
except:
print("don't do that")
We saw that we could handle a ValueError in our program. Can that exception happen in the following program? Are there any other exceptions (that we just talked about in an earlier slide) that can happen? →
# of slices in a pie
people = input("how many people are eating pizza?\n>")
print("Each person can have %s slices" % (8/int(people)))
How do we fix it (original code below)? →
# of slices in a pie
people = input("how many people are eating pizza?\n>")
print("Each person can have %s slices" % (8/int(people)))
# of slizes in a pie
people = input("how many people are eating pizza?\n>")
try:
print("Each person can have %s slices" % (8/int(people)))
except:
print("No one's gettin' nuthin'")
What if we want to deal with ValueErrors and ZeroDivisionError differently?
Say either:
You can catch specific exception types, and add an arbitrary number of except blocks for every exception type that may occur.
try:
# some tricky stuff
except NameOfErrorType1:
# handle it gracefully
except NameOfErrorType2:
# handle it gracefully too
So… let's apply that to our pizza program →
people = input("how many people are eating pizza?\n>")
try:
print("Each person can have %s slices" % (8/int(people)))
except:
print("No one's gettin' nuthin'")
people = input("how many people are eating pizza?\n>")
try:
print("Each person can have %s slices" % (8/int(people)))
except ZeroDivisionError:
print("More for me!")
except ValueError:
print("That's not a number!")
Here's a text version of three card monte.
pick a cup: 0, 1, or 2
>0
['.', 'o', 'o']
you win
pick a cup: 0, 1, or 2
>0
['o', '.', 'o']
you lose
pick a cup: 0, 1, or 2
>asdf
['.', 'o', 'o']
not a number
you lose
pick a cup: 0, 1, or 2
>400
['o', '.', 'o']
that cup doesn't exist
you lose
import random
cups = ['o', '.', 'o']
random.shuffle(cups)
n = input("pick a cup: 0, 1, or 2\n>")
result = None
print(cups)
try:
result = cups[int(n)]
except IndexError:
print("that cup doesn't exist")
except ValueError:
print("not a number")
if result == ".":
print("you win")
else:
print("you lose")