Dealing with errors¶
Interpreting error messages¶
So far in the course we have encountered a number of different types of error messages in Python, but have not really discussed how to understand what the computer is trying to tell you when you get an error message. We’ll do that below. For most Python errors you will see and exception raised when the error is encountered, providing some insight into what went wrong and where to look to fix it.
Common errors and exceptions¶
First, let’s have a look at a few different types of common Python exceptions that are displayed for different program errors.
Occurs when you attempt to reference a value with an index outside the range of values.
If the list
Occurs when you reference a variable that has not been defined.
Occurs when there is an error in your Python syntax.
Occurs when text is not properly indented when indentation is expected.
No indentation beneath a
Occurs when data of incompatible types are used in your script.
There are certainly other kinds of errors and exceptions in Python, but this list comprises those you’re most likely to encounter. As you can see, knowing the name of each error can be helpful in trying to figure out what has gone wrong, and knowing what these common error types mean will save you time trying to fix your programs.
Reading error messages¶
Let’s imagine you’ve written the script below called
wind_speed.py to convert wind speeds from km/hr to m/s and you’re dying to figure out how windy it is in Halifax, Nova Scotia, Canada where they report wind speeds in km/hr.
"""Converts wind speeds from km/hr to m/s. Usage: ./wind_speed.py Author: David Whipp - 10.10.2017 """ windSpeedKm = 50 windSpeedMs = windSpeedKm * 1000 / 3600 print('A wind speed of', windSpeedKm, 'km/hr is', windSpeedMs, 'm/s.')
Unfortunately, when you run your script you observe the following:
File "/Users/whipp/wind_speed.py", line 13 print('A wind speed of, windSpeedKm', 'km/hr is', windSpeedMs, 'm/s.) ^ SyntaxError: EOL while scanning string literal
Let’s break this example down and see what the error message says.
As you can see, there is quite a bit of useful information here.
We have the name of the script, its location, and which line was a problem.
It’s always good to double check that you actually are editing the correct script when looking for errors!
We also have the type of error, a
SyntaxError in this case, as well as where it occurred on the line, and a bit more information about its meaning.
The location on the line won’t always be correct, but Python makes its best guess for where you should look to solve the problem.
Clearly, this is handy information.
Let’s consider another example, where you have fixed the
SyntaxError above and now have made a function for calculating a wind speeds in m/s.
"""Converts wind speeds from km/hr to m/s. Usage: ./wind_speed.py Author: David Whipp - 10.10.2017 """ def convertWindSpeed(speed): return speed * 1000 / 3600 windSpeedKm = '30' windSpeedMs = convertWindSpeed(windSpeedKm) print('A wind speed of', windSpeedKm, 'km/hr is', windSpeedMs, 'm/s.')
When you run this script you encounter a new and bigger error message:
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /Users/whipp/wind_speed.py in <module>() 12 13 windSpeedKm = '30' ---> 14 windSpeedMs = convertWindSpeed(windSpeedKm) 15 16 print('A wind speed of', windSpeedKm, 'km/hr is', windSpeedMs, 'm/s.') /Users/whipp/wind_speed.py in convertWindSpeed(speed) 9 10 def convertWindSpeed(speed): ---> 11 return speed * 1000 / 3600 12 13 windSpeedKm = '30' TypeError: unsupported operand type(s) for /: 'str' and 'int'
In this case we see a
TypeError that is part of a traceback, where the problem in the code arises from something other than on the line where the code was run.
In this case, we have a
TypeError on line 11 where we try to divide a character string by a number, something Python cannot do.
TypeError indicating the data types are not compatible.
That error, however, does not occur when the code is run until line 14 where the function is used.
Thus, we see the traceback showing that not only does the error occur when the function is used on line 14, but also that the problem is in the function definition on line 11.
The traceback above may look a bit scarier, but if you take your time and read through what is written there, you will again find that the information is helpful in finding the problem in your code. After all, the purpose of the error message is to help the user find a problem :).
Assertions are a way to assert, or ensure, that the values being used in your scripts are going to be suitable for what the code does. For instance, if you have the script above for converting wind speeds, you might want to ensure that the values for the wind speed in km/hr are not negative numbers. That could be done using the following modification to the script.
"""Converts wind speeds from km/hr to m/s. Usage: ./wind_speed.py Author: David Whipp - 10.10.2017 """ def convertWindSpeed(speed): return speed * 1000 / 3600 windSpeedKm = -30 assert windSpeedKm >= 0.0, 'Wind speed values must be positive or zero' windSpeedMs = convertWindSpeed(windSpeedKm) print('A wind speed of', windSpeedKm, 'km/hr is', windSpeedMs, 'm/s.')
If you run the script above with
windSpeedKm set to be a negative number, then you get the following output:
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) /Users/whipp/wind_speed.py in <module>() 12 13 windSpeedKm = -30 ---> 14 assert windSpeedKm >= 0.0, 'Wind speed values must be positive or zero' 15 windSpeedMs = convertWindSpeed(windSpeedKm) 16 AssertionError: Wind speed values must be positive or zero
AssertionError is produced because of the
assert statement we entered in the code above.
If the condition listed after
assert is fales, the error message that follows will be printed to the screen.
More generally, assertions take on the following form:
assert <some test>, 'Error message to display'
So we start with the
assert statement, then give a logical test for some condition.
If the test is true, nothing happens and the code continues.
If not, the code stops, and an
AssertionError is displayed with the text written after the comma in the
You might also think that it would be useful to check the type of
windSpeedKm to make sure that you don’t get a
TypeError as occurred in the previous section.
It turns out that this is not really a good idea, and the philosophical idea is that the
TypeError will show that you have incompatible data types, so why raise an
AssertionError to do the same thing?
You can find a bit more information about reading error messages on the Software Carpentry and Python webpages. More information about assertions can also be found on the Software Carpentry website.