COMP 200 Resources

[Rice University]

Python Debugging Guide

There are two main types of errors that occur when executing Python programs: syntax and runtime errors.

Syntax errors:

Syntax errors occur when the Python interpreter finds an error in your code that violates Python’s “grammar” (also known as syntax) rules. Syntax errors are found before any code is actually executed so a program will not run at all if there is a syntax error in the code.

Syntax error example #1:  Unexpected Indent

This is one of the most common errors to encounter, especially when you first start working with code in a file you obtained from someone else, e.g. you downloaded an example file from the class web site.   The following is an example of what you might see in your editor:

def aFunc():    
    x = 3  # someone else's code
	y = 4  # my code

If this function is saved to a file “debug_example.py” and run in IPython, a console error message like this should come up:

This is an issue with mixing tabs and spaces. It may look like the same indentation on your editor, but Python recognizes tabs as 8 characters even though it may be displayed differently in your editor.   Above, the line 2 starts with 4 spaces while line 3 starts a tab, set to display as 4 spaces by the editor (and this code display).

To fix this problem, you should do 2 things:

  1. (Do this first!) Set your editor to use spaces for tabs.  
  2. Replace all the tabs with spaces in your code

It's easier to convert tabs to spaces and always use spaces than it is to convert to using tabs, though it is possible.

Set the editor to use spaces for tabs:

You should only need to do this once.  What this does is it tells the editor to insert 4 spaces whenever you hit the Tab key.

Replace all tags with spaces:  

You will need to do this everytime you get a file with tabs instead of spaces

 

Syntax error example #2:

def hello()
    print ‘hello'
	

If this function is saved to a file “debug_example.py” and run in IPython, a console error message like this should come up:

In IPython the name of the error is highlighted in red and a brief description of the error follows. The part of the error message above the name and description tries to tell you where the error is located. In this case, the error message states that an error was found in the file “debug_example.py” on line 1. Then the line where the error was detected is printed (the yellow line) and a pointer shows where in the line the error was detected. In the example, the pointer is right after “hello()” because a colon is missing at the end of the function header line for the “hello” function.

The pointer may not always point to the exact location of the syntax error. It just points to the location where the Python interpreter realized there was an error somewhere in the code. Make sure to look for errors on the line before the pointer as well.

 

Syntax error example #3:

aList = [1,2
aList.append(3)
print aList

If these three lines are saved to a file “debug_example.py” and run in IPython, a console error message like this should come up:

Here the message says the error is on line 2 but clearly the syntax error is at the end of line 1 since the list definition is missing a closing bracket.  This example shows that the pointer and line number given by the error message do not always point to the exact location of the error.


Runtime errors:

Runtime errors occur during the execution of a program, as opposed to syntax errors which occur before a program is executed. There are many causes of runtime errors, such as a undefined variable or insufficient memory. This type of error is more difficult to debug than syntax errors because, unlike syntax errors, it is often more difficult to pinpoint the root cause of the error.

Runtime error example #1: NameError

print x	

There is no syntax error here but when the program is run a “NameError” is created. A NameError occurs when a variable (in this case ‘x’) has not been defined before it is used. In the example, ‘x’ has not been defined so when Python tries to print ‘x’, it notices that it does not know what ‘x’ is and throws a NameError.


Runtime error example #2: IndexError

aList = []
for t in range(10):
    aList.append(t)
print aList[10]

A common error when working with lists is to get an IndexError saying that the list index is out of range. This error means that you tried to access an element in the list at an index that does not exist. This often occurs because we forget that in Python (and many other programming languages) the first element in a list is at index 0, not index 1. So in the example, the for loop appends 10 numbers to the list (indexed 0-9) but then on line 4 tries to print the 11th element (index 10), which does not exist since we only appended 10 elements. Therefore the IndexError is thrown.


Runtime error example #3: AttributeError

aList = 0
for t in range(10):
    aList.append(t)
print aList[10]

Another common error is an AttributeError. In the example, the variable ‘aList’ is set to 0. Then in the for loop, the code tries to call the ‘append’ attribute of ‘aList’, but since only lists (not integers) have the ‘append’ attribute, an AttributeError is thrown.  Therefore for this example to not have any errors, the ‘aList’ variable would have to be a list, not an integer  (plus fix the possibly remaining IndexError on line 4).


Runtime error example #4: Tracing back errors

def appendZero(list):
    aList.append(0)

def testAppendZero():
    aList = 0
    appendZero(aList)

testAppendZero() # Program starts executing here

This is a more complex example where more than one function is called as the program is executed. The resulting error message says there was an AttributeError and gives many locations for what caused the error. This type of error message, called a stack trace, shows the path the program took to reach the error. An important property of a stack trace is that the actual location where the error occurred is at the bottom of the stack trace and the parts of the program leading to that error are above it. Therefore it is most helpful to read Python stack traces from the bottom up when looking for the root cause of the error. 

In this example, the stack trace says that the error actually occurred in the appendZero function, but appendZero was called from testAppendZero. When we see this we realize the root cause of the error was that an integer, not a list, was passed into the appendZero function from testAppendZero.

There are many more types of runtime errors. If you want to know what a particular error means, search for it in the Python Errors and Exceptions Documentation or Google the error message.

Thanks to Dr. Subramanian for much of this material!