Overview

Looking for errors is a very common part of writing a program – even professional programmers typically spend about half of their time finding and fixing errors. The best approach to debugging involves testing your code incrementally as you write it. However, even if you are very careful, sometimes errors can remain hidden in your code. Recall that Chapter 1 of How to Think Like a Computer Scientist says there are three types of errors:

  1. syntax errors
  2. runtime errors
  3. semantic errors

If you don’t remember exactly what these mean, don’t worry; we’ll get more into that later. The idea to take away here is that, in the simplest sense, debugging is the process by which a programmer finds these errors and fixes them. There is no “correct” way to do this, but there are definitely some approaches that will be a lot more effective than others. This document is here to help you spend as little time debugging as possible so that you can spend more time writing code!

Exceptions explained

When your program raises an exception that you did not expect, it means you have either a syntax error or a runtime error. Don’t freak out! The great thing about these two types of errors is that the computer can usually tell you what’s wrong. Note that it can’t tell you how to fix it – that’s for you to figure out. You can never fix an error that you don’t understand (not easily, that is), which leads us to the most important step for resolving this situation:

Read the error message

Just seeing that there is red text is not enough. You need to look at what the red text says! There’s always some helpful information in there if you know how to find it. For one, the error message should be able to tell you what line the problem occurred. Keep in mind that sometimes you can encounter an error on one line which was caused on another line. This means you may want to investigate the surrounding lines as well. In any case, having the line number can really narrow down your search for the error.

Secondly, the error message will be able to tell you what it thinks went wrong. Check out the error reference to help determine what the error means. Error messages are written by other programmers just like you! They were meant to make sense, and you should definitely try to figure out what they’re trying to say.

Other errors

If your program did not raise an exception, but it doesn’t do what you want it to do, you have a semantic error. Semantic errors are not fun to debug, because you don’t have a helpful error message to point you to the issue. You do, however, have an invaluable resource to help you find the problem: you! As the creator of the program, you are more equipped than anyone to figure out why the program isn’t functioning properly. This process definitely takes practice, but there are steps you can take to avoid semantic errors and then rid your program of them when they do occur.

  1. Test tiny portions of your program often. You should not begin testing your program after you finish writing it. Testing should take place with each few lines that you write just to make sure it’s doing what you expect.
  2. Print statements are your friend. While there are many more robust debugging tools out there that you will likely encounter in the future, you can probably debug every imaginable bug in CS 1301 through the creative use of print. By printing variables at strategic points throughout your program, you can usually get a pretty good idea of where the program went wrong.
Syntax errors practice

Okay let’s try some debugging now. Syntax errors are definitely the easiest, since there are only a few you’ll regularly encounter. We’ll start there. Generally speaking, syntax errors occur when the program is formatted incorrectly in some way. Using the reference, try fixing this broken program:

reveal solution
reset
run

Ok that wasn't that hard! You may have noticed that the error you see here is a little different than what you would see in Calico. That’s because error messages are written by the creators of the compiler – this means they differ from language to language and from environment to environment. It would be impractical to try to memorize all the different types of errors, so it’s good to get into the habit of taking the time to understand them on a case by case basis.

Now let’s step it up a little. Here’s a really convoluted program that could really use some optimization. See if you can find the syntax error by using the error message:

reveal solution
reset
run

Woah! The line number was wrong!

Kind of.

While the extra parenthesis was on line 20, the error message gave us line 22, because that’s the first line to contain something other than what was expected. It turns out Python is pretty chill about line breaks in certain places. The line number in the error message got us to the right place, but keep in mind that the fix may have to take place elsewhere.

Runtime errors practice

Runtime errors are a little bit trickier due to the sheer number of them that you can encounter. A runtime error occurs when your program is formatted correctly, but has a problem when it executes. Here are come common causes of runtime errors:

  1. A variable was accessed that hasn’t been initiated
  2. A compound data type was indexed into a nonexistent position
  3. The incorrect number of parameters were used when calling a function
  4. A variable is used in the wrong context (e.g – as a string when it represents an int)
  5. An immutable datatype was treated like a mutable datatype

Let's jump right into some examples! Check this one out:

reveal solution
reset
run

You’ll notice the error message here was actually pretty helpful. With most runtime errors, Python usually has a little bit more information for you as far as what caused the problem.

Here’s another example of a runtime error:

reveal solution
reset
run

Ah curveball! Here we had two issues at once. First, we were indexing into a string at a nonexistent position. Secondly, even if that worked, you can’t change the value of a string! You can only make a new string and store it in the same place. Both of these issues are very common runtime errors.

Now for one more:

reveal solution
reset
run

Here we tried to take a string and combine it with an integer. Although this might make perfect sense to us given the context, Python wasn’t sure what to do. Should it result in a string or an int? In other words, Python has no way of knowing whether we wanted to add the string representation of the integer to the end of the string or if we wanted to add the integer value of the string to the integer. We received an error because of this ambiguity. Simply casting one of the elements is enough to make it clear which we prefer.

Semantic errors practice

Finally we have semantic errors. A semantic error exists any time your program runs to completion without raising an exception, but does not do what you want it to do. Another way of looking at this is that just because your program ‘works’ doesn’t mean it does what you want it to do! These are rarely easy to find because the problem could really be anywhere. Let’s ease into semantic errors with a simple example. You may have noticed that all of these functions have been printing Taylor Swift lyrics. Not this one though! See if you can figure out why:

hint
reveal solution
reset
run

Not bad! It looks like the creator of the program might have just written the wrong variable name in the return statement. The takeaway here is that not all semantic errors are indicative of a major issue in your code. Sometimes it’s as simple as a typo in a return statement. Let’s take on a little more complicated example:

hint
reveal solution
reset
run

This problem looks a little more complicated than a typo. In fact, it could be the result of the programmer not fully understanding how Python works. Indeed, in some languages this logic would work, but not in Python! Sometimes taking the time to understand how Python treats certain situations (like the scope of parameters) can go a long way in helping resolve semantic errors.

Exception reference
There are many exceptions that you can encounter during development. While certainly not comprehensive, this reference seeks to explain some of the more common ones you might encounter. If you don’t see your exception listed, research it online or bring your program in the TA helpdesk during office hours.
Exception Name Explanation Example(s)
AttributeError The attribute you are accessing does not exist.
ImportError An import statement is attempting to import a nonexistent module. Check the capitalization of the module. Also make sure that the module you are importing is correct for your version of Python. Sometimes module names change from version to version.
IndexError You are trying to index into a position of a compound datatype that does not exist. A very common cause of this is when your program includes a loop that runs too many times or offsets an index by too much.
KeyError The key you are accessing in a dictionary does not exist.
NameError You are accessing a variable that does not exist. The error message should tell you the name of the variable that does not have a value.
RuntimeError This error does not correspond to any one scenario – it’s more of a general catch all for weird situations. Check the error message to figure out exactly what happened. One example of a runtime error is when you have a recursive function that never ends.
SyntaxError This is exception is raised any time your syntax does not represent a valid Python program. Check the syntax errors practice for tips on finding and removing syntax errors.
TabError This rather annoying exception is raised when your program uses both tabs and spaces to represent indentation. Some programs will default to inserting a specific number of spaces when you press the tab key while others use the tab character (represented in a string like: "\t"). When you use multiple programs to edit your code (or copy/paste between different programs) you can sometimes get a mismatch. To fix this, try re-indenting the offending line(s) with the same program that the rest of the code was written in.
TypeError There are a number of situations that can cause this, but the general idea is that you are using the value of a variable in a way that it cannot be used. This can be anything from concatenating a string with an integer, to trying to change a value in an immutable datatype.
ZeroDivisionError You're dividing a number by zero.
Site by Joshua Diaddigo