Lab 8: Part 1. Tracing & Debugging Loops

Tracing refers to keeping track of the values used by a program as it runs. This can be achieved through printing, by using the debugger, or even using a pencil and paper or just your imagination. Writing an iteration table is a kind of tracing.

Debugging refers to finding and fixing errors to make something work correctly.

Testing (which we'll delve into in the following section) refers to setting up examples and establishing expectations so that we can see if something really works or not. Again it can be done by hand, or by using a program or library.

Tracing with print

The most straightforward way to trace code is to add print function calls to the code itself, so that as it runs, it prints out the information you need to know. This takes a bit of work, but it always saves time compared to simply guessing what the problem might be and trying different things.

Partner A

In the provided starter file tracing.py, there is a copy of the hasCGBlock function from the genetics problem set task (there are also several broken copies numbered hasCGBlock1 through hasCGBlock3). Your job is to add print calls so that it prints out the trace information shown in these examples (note that the provided version works correctly):

>>> hasCGBlock('CGAU')
base C True 
run 1
base G True
run 2
base A False
run 0
base U False
run 0
no blocks
False
>>> hasCGBlock('CGCAGGGCCUAGC')
base C True
run 1
base G True
run 2
base C True
run 3
base A False
run 0
base G True
run 1
base G True
run 2
base G True
run 3
base C True
run 4
base C True
found it
True

Debugger limitations

Next, we'll use Thonny's built-in debugger to trace our code, which requires less setup than using prints, and can tell us more information at once. Recall that we introduced the debugger back in lab 2. If you don't remember how it works, briefly review the "Using the debugger" section of that lab which explains how the different buttons work. The main ones we will use are the "start debugging" button, the "step into" button, and the "resume" button. Before we get started, we also need to be aware of two important limitations:

  1. The debugger will only run code in your file, not code that you put into the shell. So your file itself must call the function that you want to debug.
  2. The debugger slows things down, even when a breakpoint is set up, because it has to record every step of your program. Sometimes, when we provide very large data files, trying to import these will take forever in the debugger. In cases like this, it's best to temporarily comment out any imports for very large Python files while using the debugger, if you can. If that's not possible, you may have to rely on simpler methods like prints to trace your code.

Tracing with the debugger

The debugger can be set up to pause at certain points in the code, instead of running step by step. These are called "breakpoints." To set a breakpoint, double-click on the margin of Thonny where the line numbers are written, and a red dot should appear next to the line number you double-clicked on, which will look like this:

A screenshot of part of the Thonny window showing the first few lines of the hasCGBlock definition from the provided tracing.py file. A breakpoint has been set on line 20, which is the if statement on the first line of the for loop.

When any breakpoints are set, running the debugger will fast-forward until it reaches a line with a breakpoint on it (and it will run to completion if it never reaches such a line). It will pause at that point, and you can use the normal stepping buttons to keep running step-by-step, or you can also use the resume button to continue until the next breakpoint is hit.

By setting a breakpoint on the very first line inside of a for loop, we can use the resume button to step through each iteration of the loop. And in the function call frame window that pops up, the local variables of the function will be displayed, so we can watch the values update on each iteration, as shown in this picture:

A screenshot of Thonny showing the debugger paused on the first line of the loop in hasCGBlock, and indicating the function call frame window that's open, the yellow box in Thonny highlighting the if/else block which is about to execute, and the local variables pane at the bottom showing the value of each local variable, including base ('C'), run (0), and sequence ('CGAGGGCCUC').

Take a moment to step through the hasCGBlock loop and watch the values update so you're familiar with how to use the debugger before moving on to the next part of this lab. Remember to add a function call to the file so that it will actually run when you start it in debug mode.

Table of Contents