Dealing with Errors

We all make mistakes. Even very experienced programmers. So this lesson is all about learning to deal with the (unavoidable) errors that you will encounter when programming in Ptyhon. Indeed, most programmers spend most of their day dealing with errors of one sort or another: sometimes they are easy to solve (e.g. you mis-typed a variable name), other times they are very, very hard (e.g. you are writing a cloud computing platform and have to deal with competition for resources). Either way, learning how to find, diagnose, and resolve errors, as well as how to minimize their consequences, is thus a crucial skill for programmers.

Note: This lesson is heavily based on the official Python Documentation about Errors and Exceptions. Check it out for further examples.

Things Go Wrong

In the preceding lessons we’ve already pointed out a few simple errors and made some suggestions about how to read them, but as you have seen when there’s something wrong Python stops whatever it’s doing and prints out an error message.

Trying to run the next bit of code will produce an error message:

The error gives you a helpful clue as to what is going wrong: it’s something to do with the Syntax.

  File "<ipython-input-1-cecc6fbed5db>", line 1
    print "Ouch!"
                ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Ouch!")?

In this case it even tells you what the most likely resolution is: print("Ouch!")! Not all errors are as easy to diagnose, but by carefully reviewing the output it is often possible to get a pretty good sense of where things are going wrong.

And here’s another example:

This error also gives you a helpful clue: You can’t divide by zero!

ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-3-8cff53279792> in <module>
----> 1 45 / 0

ZeroDivisionError: division by zero

As you can see, depending on what just broke we see different error messages from the Python interpreter. Although it’s not the most crucial distinction, there are roughly two main kinds of errors: Syntax Errors and Exceptions.

Syntax Errors

A Syntax Error is likely to the be the most frequent error you encounter when you’re getting started. Syntax errors occur when the Python interpreter has trouble parsing your code. In other words, it can read what you’ve typed but it doesn’t quite make sense.

It’s a bit like when someone who doesn’t speak your language fluently makes a mistake that to you seems funny, but to them is quite natural because they’re extrapolating from what they know in a different language. Many English-speakers who are ‘embarassed’ by their level of Spanish are also apparently happy to inform Spanish-speakers that they are pregnant (‘embarazada’)! Or perhaps you think that the opposite of ‘regardless’ is ‘irregardless’? These are natural mistakes, but they are ‘errors’ nonetheless. It’s just that human beings – being smart – can figure out what you meant, while computers – being almost irredeemably stupid – cannot.

A simple typo

In the first example for instance, the error consists in a print command missing its parentheses (needed in Python3, if not Python 2):

  File "<ipython-input-4-cecc6fbed5db>", line 1
    print "Ouch!"
                ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Ouch!")?

Let’s read the error message together, from top-to-bottom:

  • First, the interpreter prints out the file name and the line number where it thinks the error can be found. In our simple case that’s not a big deal since we only have one line of code anyway, but if you had thousands of lines of code spread across dozens of separate files this could be a life-saver!
  • In addition, Python also prints the actual line where it threw up its hands and said “I can’t read this!”
  • It has even added a little ‘caret’ () to try to point out where on that line it thinks the error is. We wouldn’t recommend that you study only that bit of code (it pointed to ‘Ouch!’ after all, not to print) but it’s not a bad place to start.
  • Lastly, Python prints out very clearly that the error is something to do with the syntax and in this case even suggests the solution! (because this is a common error when people move from writing code for Python2 vs Python 3).

It really can’t get better than this. Let’s try to see if you can fix some bits of broken code by reading the errors and spotting the place where I’ve made some mistakes.

A Challenge for You!

Copy the next two code cells into a Python ‘interpreter’ and use the error messages to see if you can fix the following problems:

Hint: remember to look at what is happening before the caret!

projection="Cassini-Soldner" 
print("The " + projection + " projection preserves distances along the central meridian.")
The Cassini-Soldner projection preserves distances along the central meridian.

Exceptions

Even if your code is syntatically exemplary (i.e. it’s all perfectly written before you hit ‘run’), errors might still occur for a wide variety of reasons: your computer is freaking out, you’re not online, you haven’t defined a variable yet… Obviously, these aren’t syntax errors because your code would ordinarly work fine, it’s just that something is missing and we think this is… exceptional.

To help you find out which of the problems you’ve just hit, Python has the concept of exceptions and a huge taxonomy of specific errors (here’s a list). That way, when something exceptional happens we know whether to restart the computer, check the Internet connection, or look for the place where the variable was supposedly defined.

Let’s start by considering these two exception examples:

And:

These give:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'popn' is not defined

This happens because we tried to use popn without having given it a value!

And:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "float") to str

We’ve seen this error before: remember that programmers don’t like to write ‘string’ when they could write ‘str’, and that ‘float’ means ‘floating point number’.

And now let’s reconsider the “Division By Zero” Exception:

4 / 0

First of all we can see that every exception displays a specific message in the last line which gives you useful information about what just went wrong. That’s because exceptions are different from plain old syntax errors: they come in different types which are recognized by Python and printed accordingly. In our three examples above the Exceptions were: NameError, TypeErrorand ZeroDivisionError. These are the exception types.

As with the syntax errors, the remaining part of the error message gives us useful pointers to how to go about fixing the code:

  • Once again Python starts with the location. This time though, it doesn’t immediately point to a specific line, rather it shows the stack trace (more about this, and even more) of the operations being performed by your code when the exception occurred.
  • Luckily, there’s even an arrow (--->) pointing at the line of code where Python realised there was a problem.
<ipython-input-10-8cad47596d70> in <module>()
----> 1 print("london has an approx. popoulation of "+ popn + " million people ")

NameError: name 'popn' is not defined

In the NameError example, the problem is that we have not yet created a variable named popn (we would need something like popn = "8.5" on the line prior to printing; the 8.5 in "" to avoid the TypeError).

Do you see how these are different from Syntax Errors conceptually and that they require you to do something different? Indeed, Exceptions are clearly specified in the language for two main reasons:

  • It allows you to restrict the range of possibilities regarding what went wrong, allowing faster and easier debugging.
  • Because exceptions are “named” errors, they’re easier for the programmer to “catch” when the code is running.

In other words, you can’t know in advance whether your application will always have Internet access, so rather than just having your program ‘blow up’ or say “Can’t run, sorry!”, wouldn’t it be better if it printed a helpful message to the user saying “Hey, I don’t seem to be online. Can you check the network connection?” So in Python, one part of the application can ‘throw’ an exception (“Hey, I’m not online”) when it tries to download a file and then it’s up to the application to catch that problem and print a warning to the user.

If you see any of the following commands TRY/EXCEPT/FINALLY then that means a programmer is trying to limit the damage that could be caused by an exception.

A Challenge for You!

Run the next code cells and use the error messages to see if you can fix the following problems:

Hint: Think about the type of data that london_population holds and how to convert a number into a string with the appropriate function

london_population = 8600000
print("London's population is " + str(london_population))
London's population is 8600000

Now we want to know the ration between London and Paris populations:

  • Define variables for the number of people living in the French and British capitals (2.2 million and 8.6 million)
  • Think about the data type the result of the calculation needs to be
london_population = 8600000
paris_population = 2200000

print("The ratio of london_population to paris_population is " + str(london_population / paris_population))
The ratio of london_population to paris_population is 3.909090909090909

How to Read Errors

Here’s a “rule of thumb” list of actions to take when Python throws an error at you:

  • Don’t Panic!
  • Take a deep breath and READ CAREFULLY the error message.
  • Ask yourself: is it a Syntax Error or an Exception?
  • In both cases: where’s the faulty line?
  • For Syntax Errors: where’s the little caret character ( ‸ ) pointing at?
  • For Exceptions: what kind of exception is that? Read the Official Docs and try to make sense of it
  • No, really. Don’t Panic!

Finding Help

We can’t say this enough: Google is your friend! And we really mean it.

If learning how to interpret error messages is the first step to fixing broken code, the second one (before you think about asking for help) is doing your ‘homework’. And since you’re not the first students to learn to program, there’s a pretty good chance that someone has had your problem – or one very similar to it – before.

The largest website/community/forum online that programmers from all over the world use on a daily basis is Stack Overflow. The name itself is something of an inside joke referring to a bad situation in programming:

When a program attempts to use more space than is available on the call stack… the stack is said to overflow, typically resulting in a program crash. (source: Wikipedia )

As the name implies, it’s often the first resource that you want to consult if your program is not behaving as expected. For a quick overview of it’s features refer directly to StackOverflow’s intro section.

Often, you don’t even need to ask your question at all because the answer is already somewhere on Stack Overflow. So search the web site carefully for relevant answers before posting your question. But if, after carefully checking the site, you still can’t find an answer to your problem then it’s time to start thinking about asking your own question.

In order to maximise your chances of success (and to avoid flooding the board with unclear and repetitive questions) read thoroughly the How do I ask a good question? section and always refer to the Help Center.

This is not meant to put you off in any way, but rather to let you know the appropriate ‘netiquette’ and accetable code of conduct. Through ‘SO’, you have access to thousands of knowledgeable programmers, so it’s important to make sure you’re not wasting their time (or they can be quite short with you).

Code (Applied Geo-example)

If in the previous lessons we didn’t even leave the U.K., this time we’ll fly to the far away magical Null Island.

From its official government’s touristic office:

The Republic of Null Island
LIKE NO PLACE ON EARTH!

In order to get there, you’ll have to first solve the exercise, avoiding those pesky Syntax Errors and *Exceptions”!

longitude = str(0.0)
latitude = str(0.0)

# Null_island marker
null_island = "https://www.openstreetmap.org/?mlat="+latitude+"&mlon="+longitude+"#map=5/"+latitude+"/"+longitude

print(null_island)
https://www.openstreetmap.org/?mlat=0.0&mlon=0.0#map=5/0.0/0.0

To conclude: remember to always read the output, and try to understand what Python is telling you. You might learn a lot from these simple messages!

Further references:

For more information on the island you might watch this short video.

If you are on Twitter, don’t forget to follow the Null Island buoy!

General list or resources - Awesome list of resources - Python Docs - HitchHiker’s guide to Python - Learn Python the Hard Way - CodeAcademy

Credits!

Contributors:

The following individuals have contributed to these teaching materials: - James Millington - Jon Reades - Michele Ferretti - Zahratu Shabrina

License

The content and structure of this teaching project itself is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 license, and the contributing source code is licensed under The MIT License.

Acknowledgements:

Supported by the Royal Geographical Society (with the Institute of British Geographers) with a Ray Y Gildea Jr Award.

Potential Dependencies:

This lesson may depend on the following libraries: None