Lots of things can happen that will raise an exception in the runtime session. We depend upon this to alert us of issues in our code. It’s not something we would ever simply turn off, but try...except
allows us to at least catch the identifiable error types, that is, those we know might occur with varying user inputs, etc.
Let’s examine a Scrabble dictionary, for example…
# scrabble letter scores dictionary
letters = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ "]
points = [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1,
3, 4, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0]
lookup = dict(zip(letters, points))
We know what will happen with a wrong input, but let’s just look at it to see the error type that gets raised…
>>> lookup['a']
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
lookup['a']
KeyError: 'a'
>>>
This error was caused only because the case didn’t match, so we fix that and run it again.
letters = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ "]
letters += [x.lower() for x in letters]
points = [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1,
3, 4, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10, 0]
lookup = dict(zip(letters, points * 2))
>>> lookup['a']
1
>>> lookup['q']
10
>>> lookup['z']
10
>>> lookup[' ']
0
>>> lookup['&']
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module>
lookup['&']
KeyError: '&'
>>>
That gets rid of the case difference issue, and it doesn’t add that greatly to the data load. Sure we can address it in the code, but why go to the bother if we’ve done it here? We still have the errant input issue to deal with, as witnessed above.
def get_letter_score(letter):
return lookup[letter]
This gives us something to build upon and improve that will be re-usable.
>>> get_letter_score('&')
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
get_letter_score('&')
File ".../scrabble_letter_scores_dictionary.py", line 12, in get_letter_score
return lookup[letter]
KeyError: '&'
>>>
Note that it was the polling of the lookup
object that raised the error (we can see that identified in the error message). This is where we insert our try..except
…
def get_letter_score(letter):
try:
return lookup[letter]
except:
pass
Notice that I’ve only added except
to prevent an EOF error while parsing. It is expected with try
. We’ve not added any handling yet so won’t see an exception raised. Nothing will happen.
>>> get_letter_score('z')
10
>>> get_letter_score('&')
>>>
Now we can select the error type to isolate. All the rest will be trapped by the interpreter.
def get_letter_score(letter):
try:
return lookup[letter]
except KeyError:
return print ("Wrong alphabet!")
>>> get_letter_score('&')
Wrong alphabet!
>>>
>>> get_letter_score(a)
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
get_letter_score(a)
NameError: name 'a' is not defined
>>>
See how other exception is not interfered with?