Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I trace which function call produced an unexpected result?

Quick answer

Start at the line that produces the result, then trace back through the functions that returned it. For each call, note the call site, the values passed, the parameters those values bind to, and the returned value. Python gives each call its own local symbol table, so keep separate notes for nested calls. Compare the trace with what you expected; the first step where they differ is a useful place to investigate.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

What should I write down when a function returns something unexpected? I can see the final result, but I’m not sure which call to inspect first.

Geez

Begin with the expression that produced the final result and work toward its inputs, one call at a time. For every call, write down the exact call site, the argument values, which parameter receives each value, and the value returned to the caller. In Python, arguments are bound to the called function’s parameters, and each nested call has its own local symbol table. So a parameter name inside one function is not automatically the same value as a similarly named variable in its caller. [S1]

Here is a small example:

def add_rate(amount, rate):
    return amount + amount * rate

def total_for(price, quantity, rate):
    subtotal = price * quantity
    return add_rate(subtotal, rate)

answer = total_for(12, 3, 0.10)

Suppose you expected answer to be 36, but it is 39.6. At total_for(12, 3, 0.10), price receives 12, quantity receives 3, and rate receives 0.10. Inside that call, subtotal becomes 36. Then add_rate(subtotal, rate) passes 36 and 0.10; inside add_rate, amount is 36 and rate is 0.10. Its return value is 36 + 36 * 0.10, or 39.6. Check whether applying the rate is intended.

Follow-up question

How do I make sure I’ve mapped the arguments to the right parameters, especially if the call uses keyword arguments or several values?

Geez

Copy the call exactly as written, then annotate each supplied value beside the parameter it reaches. For positional arguments, match values to parameters in order; for keyword arguments, match by name. For example, add_rate(rate=0.10, amount=36) binds rate to 0.10 and amount to 36, even though the keywords appear in a different order from the function definition. Python supports positional and keyword argument forms. [S1]

If you are unsure which names and kinds of arguments a callable accepts, Python’s inspect.signature() can show its signature, when available. It helps check the parameter interface; it does not show the actual values from a past call or provide a complete execution trace. Some callables may not be introspectable in some implementations. [S2]

Keep a compact record, filling in values you actually observe:

call site: add_rate(subtotal, rate)
parameters: amount = [observed value]; rate = [observed value]
return: [observed value]

Do not infer a value from a variable’s name. Trace its value at the call site.

Follow-up question

What if a function calls another function several times, or I don’t know which one first introduces the wrong value?

Geez

Number the calls in execution order and record each return as it flows back to its caller. If a function is called more than once, give each call its own entry—even if the function name and parameters look the same. Label them, for example, add_rate call 1 and add_rate call 2; they may receive different values. With nested calls, note the inner call’s return before recording the enclosing function’s return.

Compare the trace with what you expected at each step, rather than checking only the final answer. In the example, confirm the subtotal is 36, then check whether the rate should be applied and whether 0.10 is intended. The first point where an observed value differs from the intended one narrows the investigation. A written trace can show where a discrepancy appears, but it cannot establish what the program should do; that expectation must come from your requirements or inputs.

Follow-up question

Can you give me a reusable tracing routine I can use on my own code?

Geez

Use this routine on a small input, and keep notes in call order:

  1. Mark the expression or statement where you observe the unexpected result.
  2. Identify the function that supplied that value, then locate its call site.
  3. Record the argument values and map each to its parameter. Note whether each argument is positional or a keyword argument.
  4. Give every nested or repeated call a separate entry. Record its values and return before moving back outward.
  5. Compare each recorded value with the expected value. Investigate the earliest mismatch, then trace again after making a change.

A reusable note can look like this:

Step [number] — call site: [expression]
Arguments: [value] -> [parameter]; [value] -> [parameter]
Return: [value]
Expected: [value or reason]

Use placeholders until you observe actual values; don’t fill gaps by guessing. If you cannot see a value at a call site, note that uncertainty and inspect the relevant caller or function next.

A practical checklist

  • Start from the statement where the unexpected result appears.

  • Copy each relevant call site exactly and note its execution order.

  • Map each argument to its parameter, including keyword names.

  • Give nested or repeated calls separate entries and record each return.

  • Compare observed and expected values to find the earliest mismatch.

A few more useful answers

Should I trace from the first function in the file?

Usually, start at the result you are investigating and follow its contributing calls back to their call sites. That keeps the trace focused on the value in question.

Does inspecting a function signature tell me what values a past call received?

No. A signature can help check a callable’s accepted parameters, when introspection is available, but it does not reveal the actual arguments or return value from a particular past call. [S2]

What if I cannot tell whether a value is wrong or merely unexpected?

Write down the expected value and why you expect it, using the relevant requirements or inputs. A trace shows where the observed result diverges; it cannot decide the intended behavior for you.

Sources

References used for this guide.

  1. [S1] Python Tutorial: More Control Flow Tools — Function calls and arguments
    docs.python.org · Checked
  2. [S2] inspect — Inspect live objects — Python 3.15.2 documentation
    docs.python.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work