Defining functions
corebeginnerdef builds a function object out of an indented block and binds a name to it. The block does not run, and its contents are not even checked for correctness, until the function is actually called.
Think of it as
def is a recipe card, not a meal. Writing the card does not cook anything — it just gives a name to a set of steps you can hand to someone later. The steps only run, and only get checked for whether the ingredients exist, when someone actually follows the card.
What we're doing: Confirm a function body does not run at def time, and that names inside it are not even checked until the call that actually needs them.
- 1–4
- def builds the function object right here. The division and the f-string inside have not run yet.
- 2
- The string right after def becomes __doc__ — data attached to the object, not a step it runs.
- 7
- Name and docstring are already available, before format_price has been called even once.
- 8–9
- One function object, called twice with different arguments — nothing about it is rebuilt.
- 13
- helper does not exist anywhere above this line. Defining call_helper does not check that — it only stores the body.
- 17
- Calling call_helper() now is what actually looks helper up, and fails because it still does not exist.
- 22
- helper is defined after call_helper — file order does not matter, only order by the time of the call.
- 26
- The exact same call_helper() now succeeds, because helper exists by the time this line runs.
format_price Convert integer cents to a display string like "$4.20".
$4.20
$1.00
name 'helper' is not defined
readyWhy this works: def does exactly two things: build a function object from the indented block, and bind a name to it. The block is not executed and its names are not resolved at that point — which is why call_helper can reference helper before helper exists anywhere in the file. Python only looks a name up inside a function body when that line actually runs, and by the time call_helper() is called a second time, helper has been defined. Calling format_price twice reuses the one object def built; nothing about defining it happens again.
Naming the function instead of calling it
Wrong
Better
What you see: The wrong version prints something like "Total: $<function calculate_total at 0x...>" — the function object itself, not a number. No error is raised anywhere.
Why: calculate_total, with no parentheses, is just the name — it refers to the function object, the same way a variable name refers to any other object. Only calculate_total(420) runs the body and produces the value the body computes. Leaving off the parentheses is not a typo Python can catch, because a bare function name is perfectly valid syntax; it just is not the call that was intended.
- def runs — builds a function object, binds a name
- the name — points at that object — nothing inside has executed
- name(...) runs — only now does the body execute, and get checked
What every function object carries
Together
Remember: def only builds a function object and binds a name to it — the body runs, and its names get checked, only when the function is actually called.
See also: names and references · none · lists

