Skip to 0 minutes and 2 secondsThrough testing, you've managed to identify several errors, but it'd be helpful if you could catch these errors, called exceptions, and handle them without halting your program, or at least display a more meaningful error message. Defensive programming is a method designed to trap exceptions and allow your program to continue working without crashing. Whilst this step may be beyond the scope of key stage three, it is a useful technique to have available to help stretch your more able students. Let's start by looking at a simplified version of our rock paper scissors game, and try and reproduce some exceptions. At the moment, we have a list of items. We have rock at position 0, paper at position 1, and scissors at position 2.
Skip to 0 minutes and 39 secondsSo let's try and put a number in that doesn't exist in my list. If I put in the number 5 and hit enter, we come up with an error message that says index error, which is telling me that I don't have a position 5 on my list. We also have a line of code that wants an input, but only wants it as an integer. So we try and put in a string instead of integer, and see what error message might occur.
Skip to 1 minute and 3 secondsSo now we have a value error, which is telling me that it needs an integer and not a string. So we're going to handle this by putting in a try. So when we type in the word try and colon, we want to indent the two lines of code that we wanted to try without an error happening. But we also need to tell it what to do if an error does happen, and this is called an exception. So we're going to except pretty much any error message that appears, and we'll put a print statement that says, oops, something has gone wrong.
Skip to 1 minute and 36 secondsSo we run it now with the same data and put a number 5. Instead of the program crashing, we now have an error message that we have customised that tells us that something has gone wrong. We had two different types of errors. We had an index error and the value error. So let's try and handle them separately, and give customised error messages depending on the error. So after except, I'm going to put in the word index error and change my message to tell my user to only put in a number that's between 0 and 2.
Skip to 2 minutes and 13 secondsSo if I try and run it again with my number 5, it tells me to only put a number in between 0 and 2. We also had a value error. So again, underneath it, making sure I'm not indented, I'm going to put except a value error. And this time, I'm going to change my error message so that it says, please enter a number and not text. So we try running this one, and type in abc. Again, our program hasn't stopped, but what it has done is it's printed out my customised error message. The article below outlines the process of creating a new subroutine for your rock paper scissors game that will handle the user input separately to your round subroutine.
Skip to 2 minutes and 58 secondsThis will make your code easier to read and debug, using try statements to handle possible exceptions. Give it a go and share your experiences in the comments section. And be sure to help out your fellow learners if they get stuck. Good luck.
You’ve managed to identify several errors by testing, but it would be helpful if you could catch these errors (called exceptions) and handle them without halting your program. At the very least, you could display a more meaningful error message. This is known as defensive programming, and is a method of trapping exceptions and allowing your program to continue working without crashing. This step may be beyond the scope of Key Stage 3, but it is a useful technique to have available to stretch more able learners.
Analysing the errors
Start by seeing if you can reproduce some of the exceptions by entering invalid data into your program. Run this Trinket with the aim of deliberately causing these exceptions to occur.
When you receive an error message, it’s important to note the type of error, as you can make your program respond differently to each. For example, the following inputs produce two different errors: an “IndexError” and a “ValueError”.
|5||IndexError: list index out of range|
|abc||ValueError: invalid literal for int() with base 10|
You can handle these exceptions by preceding some “risky” code with a
try: player = int(input("--> ")) except: print("Oops, the computer didn’t like that input")
The code above will “
try” to run the line
player = int(input("--> ")). If any exception occurs, rather than throwing up a message and stopping the code from running, the code underneath the
except statement will run instead.
Using exception handling, you can be a bit more specific about your exceptions and give different messages to the user depending on what error has occurred, by including the error type after the word
except. It would be more useful to handle your two types of error separately, as the feedback you give to the user might be different in each case. For example, if they enter text, you can tell then to enter a number; if they enter a value that is a number but isn’t within the range, you can remind them what the range is.
Adding exception handling to your rock, paper, scissors game
You’re now going to create a new subroutine that will handle the user input separately to your
round()subroutine. Again, this will make our code easier to read and debug.
Start by creating a new subroutine above your
Your intention here is to catch the error and not allow the user to continue unless they put in valid input. You’ll add a
while loop into your new subroutine and start by placing the
round() subroutine into your
def player_input(): while True: print("Type 0 for rock") print("Type 1 for paper") print("Type 2 for scissors")
The next step is to add your
try statement underneath these
try: player = int(input("--> ")) player_choice = rps_choices[player] return player_choice
Notice that again you have taken two more lines of code from your
round() subroutine, but you have added a line that returns a value. This will therefore now
try to execute the three lines of code beneath it.
The first line of code in your
round() subroutine should now look as follows:
player_choice = player_input()
You might have noticed that we have two variables named
player_choice that exist in your
player_input() subroutines. As they exist in their own subroutines, they don’t affect each other. You may want to rename one of them to avoid confusion.
Finally, you need to go back to your
player_input() subroutine and add your
except blocks. You have two possible exceptions to handle: a
ValueError and an
IndexError. You can handle these errors separately by writing two different
except statements, each time including the type of error after
except. As usual, indent your code to show it belongs to the
except statement above it.
Add two separate
except blocks under your
try statement and customise the error messages to explain how to avoid that type of error.
player_input() subroutine should now look like this:
def player_input(): while True: print("Type 0 for rock") print("Type 1 for paper") print("Type 2 for scissors") try: player = int(input("--> ")) player_choice = rps_choices[player] return player_choice except ValueError: print("Oops, looks like you entered text instead of a number. Please enter a whole number between 0 and 2") except IndexError: print("Oops, looks like you entered an incorrect number that wasn't a whole number between 0 and 2")
As you saw earlier in this step, it is also possible to simply use the word
except and not be specific about the error, as follows. It can be good to use this to catch any errors that you haven’t thought of.
except: print("An error occurred")
This doesn’t necessarily help the user understand what they did wrong, but it does stop your program from crashing if an unexpected error occurs.
You can read more about exceptions in the Python documentation.
- From your experience, can you think of any situations other than user input where exception handling could be used?
At the end of this step your code could look similar to this Trinket.