Concepts / Debugging by Tracing Execution

Debugging by Tracing Execution

Code file order (top to bottom) is not the same as execution order (the actual sequence the program runs).

  • Programming
Interactive lab

Try it: Debug by Tracing Execution

How to debug a program that runs but gives the wrong answer: compare expected and actual output, trace the lines in the order they really run with a variable watch table (or an inserted debug print), find the first line where a value goes wrong, then choose a fix and re-run to check it.

How it works

  1. State the expected output from the specification, run the program and compare: a difference is the evidence you debug from.
  2. Trace in execution order, not file order: loops repeat lines, if/elif picks one branch, and the watch table records every variable before each line runs.
  3. An inserted print('debug: ...', value) shows the same state in the output; it must not change what the program itself prints.
  4. Look for the first place a value differs from what it should be (an off-by-one range, > instead of >=, a total reset inside the loop, two names for one list, a str from input()). Where the wrong value shows up is only the symptom.
  5. Change one thing with a reason, re-run, and compare again: a fix that makes an error disappear can still leave the output wrong.

Default run (14 steps): Sum 1..n: Add up the whole numbers from 1 to n (n included) and print the sum. Press Play to trace it line by line. … Finished, but the output is wrong: got sum of 1 to 5 is 10, expected sum of 1 to 5 is 15.

Simplified: The lab's own small Python interpreter runs fixed, hand-written programs (you pick the program, the fix and a value; your text is never executed). Every program the lab can show was run in CPython 3.12 and the lab reproduces its output, its traceback text and its line-by-line trace. Six short programs, one editable value each; input() receives the value you type in the lab. Lines starting with "debug:" are ignored when comparing the output with the expected output.

Educational simulation

Loading the simulation…

The Two Orders

When debugging, it is tempting to read a program exactly as it appears in the file: first line, second line, third line, and so on. That reading order is the code file order. It is not necessarily the order in which the program runs. Execution order is the actual sequence the program follows while it runs.

StartStartFunction callConditionalConditionalLoopLoopFunction calltop to bottomtop to bottomtop to bottomnextselected pathnext
How does the order in which lines appear in a file differ from the order in which the program actually runs them?

Control-Flow Clues

Execution flow is the path a program actually takes. To follow that path, trace the program's function calls, conditionals, and loops. A function call can move execution into another part of the program. A conditional determines which path is taken. A loop can cause a part of the program to be followed repeatedly. These structures make the actual path different from a simple top-to-bottom reading.

  • At a function call, identify the function that execution enters.
  • At a conditional, identify which branch is selected.
  • At a loop, identify whether the loop continues and which part is repeated.
  • After each step, record what the program does next rather than returning automatically to the next visible line.
Program startFunction callenter called functionConditionalchoose a pathLooprepeat or continueNext operationnextreturns to flowselected branchcontinuesrepeats
What line or function runs next as control moves through a program?

A Trace in Practice

Consider a generated program structure with a starting operation, a function call, a conditional inside that function, and a loop on the selected path. The point of the example is not to read the structure as a list. Instead, follow the route that execution takes.

Worked example

Tracing the Actual Route

A program starts, calls a function, evaluates a conditional inside that function, and then follows a loop when the selected branch reaches it. How should the execution be traced?

  1. 1
    1. Start at the program entry

    Begin with the operation where execution starts. Do not assume that every item appearing above it in the file has just run.

  2. 2
    2. Enter the called function

    When the starting operation makes a function call, move to the function body. The next execution step is inside that function.

  3. 3
    3. Resolve the conditional

    At the conditional, determine which branch is selected. Trace only the path the program takes rather than treating every branch as executed.

  4. 4
    4. Follow the loop

    If the selected path reaches a loop, follow the loop's repeated path as part of the execution sequence. Record each relevant pass before moving onward.

  5. 5
    5. Continue from the resulting point

    After the function call, conditional, and loop have been traced, continue following the next operation in the route.

Result

The trace is the actual path: program start, function call, selected conditional branch, loop activity, and the next operation. This path is the execution order, even if those elements are separated or arranged differently in the file.

Program startFunction callSelected branchLoop activityObserved behavior1234
How can you follow a program's execution sequence from its starting point to the behavior you observe?

Tracing Mistakes

  • Common mistake

    Treating file order as execution order

    What it looks like

    Reading every item from the top of the file downward without following calls, branches, or repetition.

    Why it fails

    The order in the file is not necessarily the actual sequence the program runs.

    Do this instead

    At each point, identify the next operation reached by execution.

  • Common mistake

    Tracing every conditional branch as if it runs

    What it looks like

    Including both possible paths in one execution trace.

    Why it fails

    A conditional selects a path, so the actual execution trace follows the selected branch.

    Do this instead

    Determine which branch is taken and continue from that branch.

  • Common mistake

    Treating a loop as one ordinary step

    What it looks like

    Writing the loop once in the trace and immediately moving on.

    Why it fails

    A loop can make part of the execution path repeat.

    Do this instead

    Record the loop activity as repeated execution before moving to the next point.

  • Common mistake

    Ignoring function calls

    What it looks like

    Continuing with the next visible item in the file instead of entering the called function.

    Why it fails

    A function call changes where execution proceeds.

    Do this instead

    Move into the called function, trace its path, and then continue from the resulting point.

Best practice

Write a short execution trace while debugging. Each entry should describe the next function call, selected conditional path, or loop activity. This keeps attention on what the program actually does rather than on the visual arrangement of the file.

Trace Before Guessing

MEDIUM

Create an execution trace for this generated structure: the program starts, reaches a conditional, selects a branch that makes a function call, and then encounters a loop. List the execution events in the order they occur. Then explain why that order may differ from the order in which the structures appear in the file.

Hints
  • Begin at the program's starting point.
  • At the conditional, follow only the selected branch.
  • When the function call occurs, trace inside the function before continuing.
  • Include the loop's repeated activity in the execution sequence.

Why the Trace Helps

Debugging by tracing execution is a way to read a program according to its behavior. Instead of assuming that top-to-bottom file order explains everything, follow function calls, conditional choices, and loop repetition. This often provides a more sensible and effective way to understand what the program actually does, which supports both debugging and predicting program behavior.

Key Takeaways

  • Code file order and execution order are not necessarily the same.
  • Execution-flow reading follows the path the program actually takes.
  • Function calls, conditionals, and loops are key points to trace.
  • A useful trace records the next operation, selected branch, and repeated activity.
  • Understanding execution flow helps with debugging and predicting program behavior.

More concepts starting with D