Notebook-4: Dealing with Errors & Debugging

Lesson Topics:

  • Introduction to errors
    • Syntax Errors
    • Exceptions
  • How to read errors
  • Learn to find help

Welcome to the third Code Camp notebook! This lesson is all about learning to deal with the (unavoidable) errors that you wil encounter when programming in Ptyhon. 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.

DISCLAIMER: This notebook is heavily based on the official Python Documentation about Errors and Exception. Check it out for further examples.


Introduction to errors

In the preceding notebooks 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.

Run the next code cell and examine the error message:


In [ ]:
print "Ouch!"

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, our familiar "division by zero" example:


In [ ]:
45 / 0

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 fromy 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!

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


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

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


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

In [ ]:
other_projection "Mollweide"
print("In the " + other_projection + " projection, meridians are ellipses.")

Hint: which line is the error on?


In [ ]:
other_projection="Mollweide"
print("In the " + other_projection + " projection, meridians are ellipses.")

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 (run each and examine the error message returned):


In [ ]:
print("london has an approx. popoulation of "+ popn + " million people ")

What do you think is going on here?

And this one:


In [ ]:
"london has an approx. popoulation of" + 8.5 + "million people "

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:


In [ ]:
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 syntax errors because 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 but rather it explicits the stack traceback1,2 level (i.e. very roughly speaking the list of operations active in your code) where some mischief happened.

  • Luckly, there's a line reference in the following line (see the purple arrow (--->) pointing at line 1)

<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 three code cells and use the error messages to see if you can fix the following problems:


In [ ]:
london_population = 8600000
print("London's population is " + london_population)
HINT: Think about the _type_ of data that `london_population` holds _and_ how to convert a number into a string with the appropriate function

In [ ]:
london_population = 8600000
print("London's population is " + str(london_population))

In [ ]:
london_population / paris_population

HINT: Define a new variable with the amount of people living in the French capital (2.2 million)


In [ ]:
paris_population = 2200000
london_population / paris_population

In [ ]:
print("The ratio of london_population to paris_population is " + london_population / paris_population)

HINT: Think about the data type the result of the calculation needs to be


In [ ]:
print("The ratio of london_population to paris_population is " + str(london_population / paris_population))

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!

Learn to find 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 StackOverflow. The name itself is a nerdy 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 end up even needing to ask a question at all because the answer is already somewhere on Stack Overflow. 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 from the first moment what is the appropriate 'Netiquette' and accetable code of conduct that will make you stand out as competent programmer, even when you are asking for help.

Code (Applied Geo-example)


If in the previous notebook 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"!


In [ ]:
longitude = ???(0.0)
latitude ??? str(0.0)


# King's College marker
null_island = "https://www.openstreetmap.org/?mlat="+???+"&mlon="+longitude+"#map=5/"+latitude+"/"+longitude
          
prnt null_island

In [ ]:
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)

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

Credits!

Contributors:

The following individuals have contributed to these teaching materials:

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 notebook may depend on the following libraries: None