Concepts / Debugging Program Flow

Debugging Program Flow

Flow of execution is the order in which statements are executed, always proceeding from top to bottom.

  • Programming

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.

reads and storesjumps toFunction definitionFunction storedFunction bodyStatements do not runFunction callExecution enters functionFunction bodyStatements run in order
What changes when execution reaches a function definition compared with a function call?

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.

Read greet: Execution begins at the greet function definition. Python stores the function, but the print statements inside greet do not run.

Read farewell: Execution reaches the farewell function definition and stores it as well. Its print statement also does not run yet.

Start the program: The statement that prints Program starts now executes.

Call 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.

Continue between calls: The statement that prints Between calls executes next.

Call farewell: Execution jumps into farewell. Its single print statement runs, then execution returns to the statement after the call.

End 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.

nextnextnextjumpreturnnextjumpreturngreet definitionStore functiongreet bodyTwo statementsfarewell definitionStore functionfarewell bodyOne statementProgram startsRuns immediatelygreet callJump into greetBetween callsRuns after returnfarewell callJump into farewellProgram endsRuns last
What happens next when execution reaches a function definition, and how does execution move when that function is later called?

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?

  • The first function body
  • The statement between the calls
  • The second function body
Reveal answer

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.

thenfirst callreturnsecond callreturnDefinitionsStored, not runProgram startsStatementgreet bodyTwo statementsBetween callsStatementfarewell bodyOne statementProgram endsStatement
In what order do statements run when multiple functions are defined and then called in a particular sequence?

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

  • Treating a function definition as an immediate function execution

    A definition stores the function but does not run its body.

    Fix: Mark the body as executed only when a call to greet is reached.

  • Continuing on the next line while ignoring a function call

    A function call causes execution to jump into the function body first.

    Fix: Trace every statement in the function body, then return to the next line after the call.

  • Putting a function's output in definition order rather than call order

    Function bodies run when their calls are reached, and calls determine the execution order.

    Fix: Ignore 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

MEDIUM

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.
  1. Locate the first statement in the program.
  2. Move downward, marking each function definition as stored rather than executed.
  3. When an ordinary statement is reached, place it in the execution order.
  4. When a function call is reached, jump to that function's first statement.
  5. Trace the function body from top to bottom.
  6. Return to the statement immediately after the call and continue.

Keep the Jump-and-Return Model

  1. Flow of execution is the order in which statements run, normally proceeding from top to bottom.
  2. A function definition stores the function and does not execute its internal statements.
  3. A function call jumps into the function body and runs its statements in order.
  4. After the function body finishes, execution returns to the statement immediately after the call.
  5. The 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.