Debugging Program Flow
Flow of execution is the order in which statements are executed, always proceeding from top to bottom.
Follow the Execution Path
When debugging, ask one question repeatedly: what statement runs next? The flow of execution is the order in which statements are executed. In the ordinary top-to-bottom flow, execution begins with the first statement and proceeds toward the statements below it. Function definitions create an important pause in what you should expect: Python reads and stores the function, but does not immediately run the statements inside it.
Definitions Pause at the Body
Suppose execution reaches a function definition. The program reads the definition and stores the function in memory. It does not execute the statements inside the function at that moment. The flow then continues with the next statement after the definition. This is why a print statement inside a function does not produce output merely because the function has been defined.
Do not mark the statements inside a function as executed merely because the definition appeared earlier. Mark them as executed only when a call reaches that function.
Trace a Call and Return
Tracing greet and farewell
A program defines greet and farewell, then performs these statements in order: print("Program starts"), call greet("Alice"), print("Between calls"), call farewell("Alice"), and print("Program ends"). Trace the execution path.
- 1Read greet
Execution begins at the greet function definition. Python stores the function, but the print statements inside greet do not run.
- 2Read farewell
Execution reaches the farewell function definition and stores it as well. Its print statement also does not run yet.
- 3Start the program
The statement that prints Program starts now executes.
- 4Call greet
Execution jumps into greet. Its two statements run in order, producing Hello, Alice and Welcome!. After the function body finishes, execution returns to the statement after the call.
- 5Continue between calls
The statement that prints Between calls executes next.
- 6Call farewell
Execution jumps into farewell. Its single print statement runs, then execution returns to the statement after the call.
- 7End the program
The statement that prints Program ends executes last.
The output order is Program starts, Hello, Alice, Welcome!, Between calls, the farewell message, and Program ends. The function bodies appear in the output only when their calls are reached.
The important pattern is jump, run, and return. A call does not mean that execution simply continues with the next statement. The call sends execution into the function body. Every statement in that body runs in order. When the body finishes, execution resumes at the exact statement immediately after the call.
Predict Multiple Calls
What do you think happens?
A program defines two functions, then calls the first function, performs a statement between the calls, and calls the second function. Which event happens first: the statements inside the first function, the statement between the calls, or the statements inside the second function?
Reveal answer
The first function body
When the first call is reached, execution jumps into that function and runs its body before returning to the statement after the call. The statement between the calls runs next, and the second function body runs only when the second call is reached.
For a program with several functions, first mark the definitions as stored rather than executed. Then read the statements below those definitions from top to bottom. Whenever you reach a call, temporarily follow the called function's body from its first statement to its last statement. After that body finishes, return to the next statement after the call and continue the trace.
Mistakes in Flow Tracing
Common mistake Treating a function definition as an immediate function execution
What it looks likeCounting the statements inside greet as executed as soon as Python reaches the greet definition
Why it failsA definition stores the function but does not run its body.
Do this insteadMark the body as executed only when a call to greet is reached.
Common mistake Continuing on the next line while ignoring a function call
What it looks likeMoving directly from the call to the statement after it without tracing the called function
Why it failsA function call causes execution to jump into the function body first.
Do this insteadTrace every statement in the function body, then return to the next line after the call.
Common mistake Putting a function's output in definition order rather than call order
What it looks likeExpecting farewell's statement to run before greet because farewell was defined nearby
Why it failsFunction bodies run when their calls are reached, and calls determine the execution order.
Do this insteadIgnore the bodies during definition and place each body into the trace at its call.
When debugging, write a short execution trace. Record definitions as stored, record ordinary statements when they are reached, and indent or otherwise separate the statements followed inside each function call. This makes the jump into a function and the return to the caller visible.
Practice the Trace
Create an execution trace for a program that defines two functions, reaches a statement before its first call, calls the first function, reaches a statement between the calls, calls the second function, and then reaches a final statement. Label each function definition as stored rather than executed. Then list the function body statements at the point where each call occurs.
Hints
- Begin with the first statement and move downward.
- Do not execute either function body at its definition.
- At each call, trace the called function body before continuing after the call.
- 1Locate the first statement in the program.
- 2Move downward, marking each function definition as stored rather than executed.
- 3When an ordinary statement is reached, place it in the execution order.
- 4When a function call is reached, jump to that function's first statement.
- 5Trace the function body from top to bottom.
- 6Return to the statement immediately after the call and continue.
Keep the Jump-and-Return Model
- 1Flow of execution is the order in which statements run, normally proceeding from top to bottom.
- 2A function definition stores the function and does not execute its internal statements.
- 3A function call jumps into the function body and runs its statements in order.
- 4After the function body finishes, execution returns to the statement immediately after the call.
- 5The order of function calls determines where each function body appears in the overall execution trace.
Key Takeaways
- Execution follows statements from top to bottom unless a function call temporarily moves control into a function body.
- Function definitions are stored; their internal statements do not run during definition.
- Function calls run the function body before execution returns to the next statement after the call.
- To debug program flow, trace definitions, ordinary statements, calls, function bodies, and returns in that order.