This lesson introduces the def statement with its header and indented body, separates defining a function from calling one, traces the detour a call makes through the flow of execution, and distinguishes a parameter from an argument.
Subject: Python · 65 slides · code lesson
Open the interactive version of this deck
Title
Python · Chapter 3 — Functions
§3.4-3.7, pp. 19-21
Objectives
Five things, each one you can check yourself at an interpreter prompt.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 19-21 — the pages these objectives are drawn from
Warm-up
Functions exist because some sequences of statements deserve a name. Find one.
Discussion prompt
Think of any three-or-four-line sequence you have written or read in this course so far that you might want to do more than once. Describe it in three words, as though naming it.
Hint: The name is the point. If you can name it, it probably wants to be a function.
Answer:
Printing a heading, converting a temperature, showing a value twice — any of these is a candidate.
Notice what naming did: it let you refer to four lines with three words, and it let you talk about the sequence without listing it.
That is the whole benefit, and this lesson is about the syntax for claiming it. A function is a named sequence of statements that performs a computation — you have had the definition since lesson 3a, and now you get to write one.
Concept
A function definition specifies the name of a new function and the sequence of statements that run when the function is called. Those two things happen at two different times, and keeping them apart is what this whole lesson is for.
function definition — A statement that creates a new function, specifying its name, its parameters, and the statements it contains.
Function definitions get executed just like other statements, but the effect is to create function objects. The statements inside the function do not run until the function is called, and the definition itself generates no output.
Figure (svg): Two columns contrasting what happens when a definition runs with what happens when a call runs
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 19-20
Section
Section 1
Concept
The keyword def indicates that this is a function definition. The first line is called the header; the rest is called the body. The header has to end with a colon and the body has to be indented.
header — The first line of a function definition: the keyword def, the name, the parentheses and the colon.
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")| Part | What it is | Note |
|---|---|---|
| def | the keyword that starts a definition | required |
| print_lyrics | the name of the new function | same rules as variable names |
| () | empty: this function takes no arguments | required even when empty |
| : | ends the header | required |
| print(...) | the body, indented four spaces | runs only when called |
By convention, indentation is always four spaces. The body can contain any number of statements. The rules for function names are the same as for variable names: letters, numbers and underscore are legal, the first character cannot be a number, and you cannot use a keyword.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 19-19
Picture it
The colon at the end of the header and the indentation of the body are what tell Python where the function starts and stops.
Figure (svg): Two columns showing the header line of a definition and the indented body beneath it
Every compound statement in Python has this shape — a header ending in a colon, then an indented block. You will meet the same shape for if in chapter 5 and for loops in chapter 7.
Worked example
Two separate things happen here. Watch when the output appears.
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
print_lyrics()| Lines | What happens | Effect |
|---|---|---|
| 1-3 | the definition runs | a function object is created; NO output |
| 5 | the call runs | the body's two statements run |
| output | two lines | both from inside the function |
Run the definition and notice the silence.
Why: The definition generates no output. Three lines executed and nothing appeared, which is exactly right.
Run the call.
Why: The syntax for calling the new function is the same as for built-in functions: the name, then parentheses.
Account for the two lines of output.
Why: Both came from the body. Each print inside the function ran once, in the order they are written.
Figure (svg): The state of the program after each line of Worked example writing a definition and calling it, drawn as a ladder with one rung per traced line
Two lines of output, both produced by the call on line 5. The definition on lines 1 to 3 produced nothing at all — it created the function rather than running it.
Verify: Delete the last line and run the file again.
Why: Nothing is printed. That is the cleanest possible demonstration that a definition runs nothing: the body is still there, still correct, and still silent, because nothing called it.
Prediction
You have seen this pattern before, with assignment in lesson 2a.
Predict first
You type a three-line function definition into a script and run it. What appears on the screen?
Correct: Nothing at all — the definition generates no output.
Why: A function definition is executed like any other statement, but its effect is to create a function object and bind a name to it. The statements inside the body do not run until the function is called, so none of their output appears. This is the same shape as an assignment: an effect with no visible result, and silence is the correct outcome rather than a symptom.
Worked example
The book uses double quotes here for a specific reason. Work out what it is.
print("I'm a lumberjack, and I'm okay.")
print('I am a lumberjack, and I am okay.')| Version | Why | Result |
|---|---|---|
| double quotes outside | the apostrophes inside are ordinary characters | works |
| single quotes outside | would end the string at the apostrophe | would break |
| the rule | single and double quotes do the same thing | choose the one the text does not contain |
Notice the apostrophes in the text.
Why: I'm contains a single quote, which is also an apostrophe.
See what would happen with single quotes outside.
Why: The string would end at the apostrophe in I'm, and the rest of the line would be leftover text Python could not parse.
State the rule.
Why: Single quotes and double quotes do the same thing; most people use single quotes except in cases like this, where a single quote appears in the string.
Figure (svg): Two columns showing a string with an apostrophe delimited by double quotes and the broken version delimited by single quotes
Double quotes, because the text contains apostrophes. The two kinds of quotation mark are interchangeable, which is precisely so that you can pick whichever one is not inside your text.
Verify: Check the constraint-challenge answer from lesson 1b against this.
Why: That probe predicted exactly this fix — use double quotes when the message contains a single quote — and here the book uses it in real code. A prediction from one lesson confirmed by the next chapter's practice is worth noticing.
Error analysis
One is correct. Mark what is wrong with the other three.
Annotate
The indentation error is the one worth causing on purpose once. It is the first time in this course that whitespace changes the meaning of a program.
Faded example
Two characters are missing, and both are required rather than conventional.
Fill in the blanks
def greet():
print('Hello!')
Why: The empty parentheses indicate that this function does not take any arguments — they are required even when there is nothing to put in them, because they are what make it a function definition rather than something else. The colon ends the header and announces that an indented block follows. Omitting either is a syntax error, and neither is a matter of style.
Sorting
The rules are the same as for variable names, which you already know.
Sort into buckets
Sort each proposed function name.
Socratic
Most languages use braces. Python uses whitespace, and there is a reason.
Discussion prompt
Python could have marked the end of a function body with a keyword like end. What does using indentation instead buy, and what does it cost?
Hint: Think about what programmers do to code anyway, in every language.
Answer:
It buys agreement between what the code looks like and what it means. In a language with braces, you can indent a line misleadingly and the indentation lies about the structure; in Python that is impossible, because the indentation IS the structure.
It costs you the ability to be careless with whitespace. Mixing tabs and spaces, or losing indentation when pasting code, changes the meaning of a program rather than merely its appearance.
The convention of four spaces exists to make the cost small: if everybody uses the same amount, code from different sources lines up. This is why the book states the convention as though it were a rule.
Section
Section 2
Concept
Defining a function creates a function object, which has type function. The name of the function is a variable that refers to that object — which is exactly the state-diagram picture from lesson 2a, with a function on the right of the arrow instead of a number.
>>> def print_lyrics():
... print('a')
...
>>> print(print_lyrics)
<function print_lyrics at 0xb7e99e9c>
>>> type(print_lyrics)
<class 'function'>| What you write | What it means | What you get |
|---|---|---|
| print_lyrics | the name, with no parentheses | the function object itself |
| type(print_lyrics) | asking its type | class function |
| print_lyrics() | the name WITH parentheses | runs the body |
If you type a function definition in interactive mode, the interpreter prints dots to let you know the definition is not complete. To end the function, you have to enter an empty line.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 20-20
Picture it
Nothing new is happening here. A name refers to a value, and this time the value is a function.
Figure (svg): A state diagram showing the name print_lyrics with an arrow pointing at a function object, alongside n pointing at seventeen
This is why the parentheses matter so much: without them you have the value, and with them you run it. Lesson 3a made the same point about math.sqrt, and it is the same fact.
Worked example
Once a function is defined, its name is available inside other definitions.
def print_lyrics():
print("I'm a lumberjack, and I'm okay.")
print("I sleep all night and I work all day.")
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()| Lines | What happens | Effect |
|---|---|---|
| 1-3 | define print_lyrics | no output |
| 5-7 | define repeat_lyrics | no output |
| 9 | call repeat_lyrics | which calls print_lyrics twice |
| output | four lines | two per call of print_lyrics |
Notice that the second definition uses the first.
Why: Once you have defined a function, you can use it inside another function. There is nothing special about doing so — the name is just available.
Count the output.
Why: repeat_lyrics calls print_lyrics twice, and each of those prints two lines, so four lines appear.
Notice which lines produced output.
Why: Only line 9. Both definitions were silent, exactly as before, and all four lines of output came from the single call at the bottom.
Figure (svg): A call diagram showing repeat_lyrics calling print_lyrics twice, with two lines of output from each
Four lines of output, all from the one call on line 9. The two definitions produced nothing, and the doubling came from repeat_lyrics calling print_lyrics twice.
Verify: Count the print statements in the file and compare with the output.
Why: There are two print statements and four lines of output. The counts no longer match — which, as in lesson 1a, is the signature of something running more than once. Here it is a function called twice rather than a loop, but the diagnostic is the same.
Prediction
The definition is correct. Look at what happens after it.
def greet():
print('Hello')
greet| Lines | What happens | Output |
|---|---|---|
| 1-2 | the definition | creates the function, no output |
| 4 | the name with NO parentheses | a bare expression |
| script mode | a bare expression is discarded | no output |
Predict first
What does this script display?
Correct: Nothing — the last line is a bare expression naming the function without calling it, and bare expressions are silent in a script.
Why: Two rules combine, one from each of two lessons. The name without parentheses refers to the function rather than calling it, so the body never runs. And a bare expression in script mode is evaluated and discarded, so even the function object is not displayed. At the interactive prompt the same file would show the function object — which is why this bug behaves differently depending on how you run it.
Worked example
Defining a function at the prompt looks different from defining one in a file. Read the difference.
>>> def print_lyrics():
... print('first line')
... print('second line')
...
>>>| Prompt | What it means | What to do |
|---|---|---|
| >>> | the normal prompt | start a new statement |
| ... | the continuation prompt | the definition is not finished |
| empty line | ends the definition | back to the normal prompt |
Recognise the second prompt.
Why: If you type a function definition in interactive mode, the interpreter prints dots to let you know that the definition is not complete.
Keep typing the body.
Why: Every indented line belongs to the function. The dots keep appearing because Python is still waiting to find out where the body ends.
End it with an empty line.
Why: To end the function you have to enter an empty line. In a file this is unnecessary — the end of the indentation is enough — which is why this only arises at the prompt.
Figure (svg): The state of the program after each line of Worked example the interactive-mode dots, drawn as a ladder with one rung per traced line
The dots are a continuation prompt, meaning the statement is not finished. An empty line ends the definition and the normal prompt returns.
Verify: Check that the function exists afterwards.
Why: Typing print_lyrics at the prompt now displays a function object rather than a NameError. Getting the ordinary prompt back does not by itself prove the definition worked, so checking the name is the confirmation.
Trap
Wanting to run print_lyrics, a student writes the name on a line by itself.
Treat the name as the instruction
Why: In English, naming an action and asking for it are often the same thing.
In a script, nothing happens at all: the line is a bare expression, which is evaluated and discarded. At the prompt it displays a function object, which looks like an error and is not.
The parentheses are the operator that means call this.
Write the name to refer to the function; add parentheses to run it
Why: Both are legal and they mean different things — which is exactly the math.sqrt versus math.sqrt(2) distinction from lesson 3a.
If nothing happened, check for the parentheses first
Why: A silent script whose function body contains print statements is nearly always a call that was never made.
The displayed function object is genuinely informative when it happens: it tells you the name exists and refers to a function, which rules out a typo in the name.
Discrimination
The parentheses decide. Sort on that alone.
Sort into buckets
For each line, does the function's body run?
Matching
Four expressions built from one function name. Match each to its result.
Match the pairs
Why: The pattern is entirely mechanical: parentheses after greet mean the body runs, and no parentheses mean it does not. The fourth is the interesting one — the body runs, producing output, and THEN its return value is asked about, giving NoneType. That None is the subject of lesson 3c, and meeting it here as a puzzle makes it less surprising there.
Explain it to yourself
The state diagram said yes. Make sure you believe it.
Discussion prompt
In what sense is a function a value like 17 or 'hello'? Give two things you can do with a function that you can also do with an integer, and one thing you can do with a function that you cannot do with an integer.
Hint: Think about names, and about type().
Answer:
You can bind a name to it, and you can ask type() about it. Both work identically for 17 and for a function object, which is what the state diagram was showing.
What you can do with a function and not with an integer is call it — put parentheses after it and have something happen. Trying that on an integer gives int object is not callable, which is the same message as math.pi() from lesson 3a.
The reason this is worth being clear about is that chapter 19 will pass functions to other functions as arguments. That only makes sense if a function really is a value, and the evidence for that is already on this slide.
Section
Section 3
Concept
Function definitions get executed just like other statements, so they run in order like everything else. As you might expect, you have to create a function before you can run it — in other words, the function definition has to run before the function gets called.
def print_lyrics():
print('lyrics')
def repeat_lyrics():
print_lyrics()
print_lyrics()
repeat_lyrics()| Lines | What happens | Requirement |
|---|---|---|
| 1-2 | define print_lyrics | the name now exists |
| 4-6 | define repeat_lyrics | its body is not checked yet |
| 8 | call repeat_lyrics | which needs print_lyrics to exist NOW |
The book sets two exercises here that are worth doing rather than reading about: move the last line to the top and see what error you get, then move the definition of print_lyrics after the definition of repeat_lyrics and see what happens. The two experiments have different answers, and the difference is the whole point.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 20-21
Picture it
One rearrangement breaks the program and the other does not. Predict which before looking.
Figure (svg): Two columns showing the call moved to the top, which fails, and one definition moved after another, which works
The right-hand column surprises people. repeat_lyrics mentions print_lyrics before it is defined, and that is fine — because the mention is inside a body, and bodies are not run until they are called.
Worked example
The book's first exercise. Predict the error before advancing.
repeat_lyrics()
def print_lyrics():
print('lyrics')
def repeat_lyrics():
print_lyrics()| Line | What happens | Consequence |
|---|---|---|
| 1 | call repeat_lyrics | but nothing has defined it yet |
| result | NameError: name 'repeat_lyrics' is not defined | the program stops |
| 3-7 | never reached | the definitions never run |
Start at line 1 as always.
Why: Execution always begins at the first statement of the program, so the call is the first thing attempted.
Look up the name.
Why: Nothing has created repeat_lyrics yet — the def statement that would create it is four lines below and has not run.
Read the error.
Why: A NameError, which is the same error you would get from using any undefined name. Python does not distinguish not defined yet from never defined.
Figure (svg): The state of the program after each line of Worked example the first experiment, calling too early, drawn as a ladder with one rung per traced line
A NameError on line 1. The definitions never run, because the program stops at the first error, so the file is no better off for containing them.
Verify: Compare with what happens if you use an undefined variable.
Why: Using an undefined variable gives the same NameError, with the same wording. Function names are ordinary names — the state diagram said so — and this error is the same error, which is why no new concept is needed to explain it.
Prediction
The function mentions a name that does not exist anywhere.
def show():
print(missing_name)
print('before')| Lines | What happens | Result |
|---|---|---|
| 1-2 | the definition runs | no error; the body is not checked |
| 4 | print('before') runs | displays before |
| never | show is never called | the bad name is never looked up |
Predict first
What does this script do?
Correct: It prints 'before' and exits with no error, because show is never called and its body is never run.
Why: The definition creates a function object without examining what the body refers to. Since nothing ever calls show, the name missing_name is never looked up, and no error occurs. This is genuinely useful to know: a Python file can contain a completely broken function and run perfectly, right up until somebody calls it.
Worked example
The book's second exercise, and the answer surprises most readers.
def repeat_lyrics():
print_lyrics()
print_lyrics()
def print_lyrics():
print('lyrics')
repeat_lyrics()| Lines | What happens | Why it works |
|---|---|---|
| 1-3 | define repeat_lyrics | its BODY is not run and not checked |
| 5-6 | define print_lyrics | the name now exists |
| 8 | call repeat_lyrics | its body runs NOW, and print_lyrics exists |
Notice what line 2 does when the definition runs.
Why: Nothing. The statements inside the function do not run until the function is called, so the mention of print_lyrics on line 2 is not looked up yet.
Run the second definition.
Why: By line 6, both names exist.
Run the call.
Why: Now the body of repeat_lyrics executes, and when it reaches print_lyrics that name has existed for two lines. It works.
Figure (svg): A flow chart showing definitions being executed in order and then a call causing the body to run, with the name lookup happening at call time
It runs correctly. A function body may mention a name that does not exist yet, as long as the name exists by the time the body actually runs.
Verify: Delete the definition of print_lyrics entirely and see when the error appears.
Why: The file still defines repeat_lyrics without complaint, and the NameError appears only when repeat_lyrics is called. That the error waits until the call is proof that bodies are genuinely not examined at definition time — which is the fact this experiment exists to establish.
Trap
A student writes a function that calls a helper they have not written yet, runs the file, sees no error, and concludes the helper must exist somewhere.
Assume that no error means everything referenced is present
Why: In many languages a compiler would indeed check this before running anything.
Python does not. The definition succeeds regardless of what the body mentions, and the error waits until the body actually runs — possibly much later, possibly only for certain inputs.
A definition creates an object. It does not verify the body.
Expect name errors at CALL time, not at definition time
Why: Which means a file can import cleanly and still fail the moment a particular function is used.
Call every function you write at least once
Why: This is the only way to find out whether its body actually works, and it is one reason the book's development method in chapter 6 tests as it goes.
The upside of the same rule is the second experiment: functions may refer to each other in any order, which makes it possible to write two functions that call each other at all.
Ranking
Four lines, one working arrangement. Definitions before the call that needs them.
Put in order
Why: The only hard requirement is that the call to main comes after main is defined. Beyond that there is freedom: helper could be defined after main, because main's body is not run until it is called. The order given here is the conventional one — a bit of setup, then definitions, then the call that starts everything — and conventions like this exist so that a reader does not have to check whether the order is legal.
Step zero
A structural decision that every Python file makes.
Discussion prompt
You are writing a script with three function definitions and one line that starts everything off. Where does that line go, and what would go wrong if you put it between the second and third definitions?
Hint: Ask which definitions have to have run by then.
Answer:
It goes at the bottom, after all three definitions. That is the arrangement that is guaranteed to work regardless of which functions call which.
Putting it between the second and third definitions works ONLY if nothing reachable from that call needs the third function. Since that depends on the whole call graph, it is a fact you would have to re-check every time you edited any of the three.
So the bottom is not merely conventional. It is the only position whose correctness does not depend on details that change as the program grows — which is a good reason for a convention to exist.
Counterexample
The rule is about time, not about position. Show that the two differ.
Discussion prompt
Construct a program where a function is USED on a line that appears above the line defining it, and yet the program runs correctly. Explain why it works.
Hint: The second experiment in this section is one. Find the general principle.
Answer:
Any pair of mutually referring functions does it: def a(): b() written above def b(): print('hi'), with the call to a at the bottom.
It works because the mention of b inside a's body is not looked up when a is defined — only when a is called, by which time b exists.
The principle: the rule is that the definition must EXECUTE before the call executes, not that it must appear earlier in the file. The two coincide for top-level calls, which is why the shorter version of the rule is usually good enough — but functions calling each other is exactly the case where they come apart.
Section
Section 4
Concept
To ensure that a function is defined before its first use, you have to know the order statements run in, which is called the flow of execution. Execution always begins at the first statement of the program, and statements are run one at a time in order from top to bottom.
flow of execution — The order in which statements run.
In summary, when you read a program you do not always want to read from top to bottom. Sometimes it makes more sense to follow the flow of execution.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 21-21
Picture it
The flow leaves the main line, does some work, and comes back to exactly the point it left.
Figure (svg): A flow chart showing execution running down a program, jumping into a function body, running it, and returning to the line after the call
The crucial word is back. A call is not a jump to somewhere else; it is a jump that returns, which is what makes functions composable at all.
Worked example
Write down the order in which the print statements run before advancing.
def greet():
print('B')
print('A')
greet()
print('C')| Line running | What happens | Output |
|---|---|---|
| 4 | print('A') | A |
| 5 | call greet: detour into the body | - |
| 2 | print('B') inside the function | B |
| 5 | the body ends: return to the call site | - |
| 6 | print('C') | C |
Start at the first statement that is not a definition.
Why: The definition on lines 1 to 2 creates the function and runs nothing, so execution effectively begins at line 4.
Follow the detour.
Why: At line 5 the flow jumps into the body, runs line 2, and reaches the end of the body.
Follow the return.
Why: The flow comes back to pick up where it left off — line 6, the statement after the call.
Figure (svg): A call diagram showing the main flow printing A, calling greet which prints B, and returning to print C
A, then B, then C. The output is in the order the flow visits the print statements, which is not the order they appear in the file.
Verify: Read the file top to bottom and note that the order differs.
Why: Reading the page gives B, A, C — the order the lines are written. The actual output is A, B, C. That mismatch is exactly why the book says you do not always want to read a program from top to bottom, and following the flow is the alternative it recommends.
Invariant
Step through and say, at each frame, which line is currently running.
Step through it
At frame 3, how many functions are paused waiting to resume — and where will the flow go when inner finishes?
Two things are paused at frame 3: outer, at line 6, and __main__, at line 9. Python keeps track of both, which is why it can return through them in the right order. Lesson 3c draws this as a stack diagram.
Worked example
Two levels deep. Track where the flow is at each moment.
def inner():
print('inner')
def outer():
print('outer start')
inner()
print('outer end')
outer()| Line | What happens | Output |
|---|---|---|
| 9 | call outer | flow enters outer |
| 5 | print('outer start') | outer start |
| 6 | call inner | flow enters inner |
| 2 | print('inner') | inner |
| 7 | inner returns; outer continues | outer end |
Enter the first detour.
Why: The call on line 9 sends the flow into outer's body.
Enter the second detour from inside the first.
Why: While in the middle of one function, the program has to run the statements in another. That is line 6.
Come back twice.
Why: inner finishes and the flow returns to line 7, still inside outer. Then outer finishes and the flow returns to line 9, which is the end of the program.
Figure (svg): The state of the program after each line of Worked example a detour inside a detour, drawn as a ladder with one rung per traced line
outer start, inner, outer end. The flow went two levels deep and came back out through both, resuming each function exactly where it had paused.
Verify: Check that outer end printed after inner rather than before.
Why: It did, which proves the flow genuinely returned into the middle of outer rather than abandoning it. If a call did not come back, outer end would never appear — and that is the difference between a call and a jump.
Trap
Asked what a program outputs, a student reads the print statements top to bottom and lists them in that order.
Assume the order on the page is the order of execution
Why: For a program with no functions it is, which is why the habit forms in chapters 1 and 2.
With functions, the order on the page and the order of execution come apart completely. A print inside a definition near the top may run last, or never.
Follow the flow of execution, which is a different reading order.
Skip the definitions on the way down
Why: They create objects and run nothing. Note the names they create and move on.
At each call, jump to the body, read it, and come back to the line after the call
Why: That is the detour, and it is what turns file order into execution order.
This is the reading skill the section exists to teach, and it is worth practising deliberately: put your finger on the line the flow is at, and move it.
Prediction
Follow the flow rather than the page.
def f():
print(2)
print(1)
f()
print(3)| Line | What runs | Output |
|---|---|---|
| 4 | print(1) | 1 |
| 5 | call f, run its body | 2 |
| 6 | print(3) | 3 |
Predict first
In what order do the numbers appear?
Correct: 1, 2, 3 — the flow prints 1, detours into f to print 2, then returns and prints 3.
Why: The numbers were deliberately chosen so that execution order and file order disagree: on the page the 2 appears first. Following the flow gives 1, 2, 3, which is the answer, and reading the page gives 2, 1, 3, which is not. This is the shortest possible demonstration of why the two reading orders are different skills.
Analogy
Match each part of a function call to the part of the journey it corresponds to.
Match the pairs
Why: The analogy is exact in the way that matters: you rejoin at the point you left, not at the start and not further along. Where it breaks down is that a detour can contain another detour to any depth, and the driver always remembers every junction — which is the part Python handles for you and which lesson 3c makes visible as a stack of frames.
Edge cases
Nothing in the rules forbids it. Work out what would happen.
Discussion prompt
The rule says a call detours into the body and comes back. What happens if the body contains a call to the same function? Describe the flow, and say whether it ever comes back.
Hint: Apply the rule literally, twice, and then again.
Answer:
The flow detours into the body, reaches the call, and detours into the body again — the same body, but a fresh detour that will have to come back separately.
With nothing to stop it, this repeats forever, and Python eventually stops it with a RecursionError because it cannot keep track of unlimited paused calls.
With something to stop it — a condition that skips the inner call in some case — it becomes recursion, which is one of the most powerful ideas in the book. Chapter 5 introduces it properly, and the flow rule you have just applied is the whole mechanism. Nothing new is needed.
Section
Section 5
Concept
Some of the functions you have seen require arguments. Inside the function, the arguments are assigned to variables called parameters. The two are different things and the book keeps two words for them.
parameter — A name used inside a function to refer to the value passed as an argument.
def print_twice(bruce):
print(bruce)
print(bruce)| Piece | Which word | Meaning |
|---|---|---|
| bruce | the PARAMETER, named in the header | a name the function uses |
| print_twice('Spam') | 'Spam' is the ARGUMENT | supplied by the caller |
| inside the body | bruce refers to 'Spam' | for this call only |
This function assigns the argument to a parameter named bruce. When the function is called, it prints the value of the parameter — whatever it is — twice. The function works with any value that can be printed.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 21-22
Picture it
The value crosses into the function. The name it had outside stays outside.
Figure (svg): A diagram showing the caller's variable michael and the function's parameter bruce both pointing at the same string value
The book puts it memorably: it does not matter what the value was called back home in the caller; here in print_twice, we call everybody bruce.
Worked example
The parameter is a name; whatever arrives becomes what it refers to.
>>> print_twice('Spam')
Spam
Spam
>>> print_twice(42)
42
42
>>> print_twice(math.pi)
3.141592653589793
3.141592653589793| Argument | Its type | What bruce refers to |
|---|---|---|
| 'Spam' | a str | bruce refers to 'Spam' |
| 42 | an int | bruce refers to 42 |
| math.pi | a float | bruce refers to that float |
Notice that the function was not changed.
Why: One definition, three calls, three different types of argument. Nothing about the definition mentions a type.
See what the parameter does.
Why: It is a name that refers to whatever was passed. On each call it refers to something different, and the body does not care.
State the scope of the claim.
Why: The function works with any value that can be printed — which, since print accepts anything, means any value at all.
Figure (svg): The state of the program after each line of Worked example one function, four different arguments, drawn as a ladder with one rung per traced line
All three work, printing each argument twice. The parameter is a name, not a type, and the function is written in terms of what it does rather than what it is given.
Verify: Pass something for which printing is unusual and check the claim holds.
Why: print_twice(print_twice) prints the function object twice. That the function accepts even a function as its argument confirms there is no type restriction at all — which is a stronger check than three ordinary values.
Prediction
The caller's variable has a completely different name from the parameter.
def print_twice(bruce):
print(bruce)
print(bruce)
michael = 'Eric, the half a bee.'
print_twice(michael)| Line | What happens | State |
|---|---|---|
| michael = ... | creates a name in __main__ | michael -> the string |
| print_twice(michael) | the VALUE is passed | bruce -> the same string |
| the body | prints bruce twice | two identical lines |
Predict first
What happens when this runs?
Correct: It prints the sentence twice. Only the value is passed; the names are unrelated.
Why: The parameter bruce is created by the call itself and set to refer to whatever the argument evaluated to. The caller's name for that value, michael, never enters the function and is not needed there. If the names had to match, a function could only ever be called with one variable, which would make functions almost useless.
Worked example
This is the composition rule from lesson 3a, and it applies to your own functions too.
>>> print_twice('Spam ' * 4)
Spam Spam Spam Spam
Spam Spam Spam Spam
>>> print_twice(math.cos(math.pi))
-1.0
-1.0| Argument expression | When it is evaluated | What the body sees |
|---|---|---|
| 'Spam ' * 4 | evaluated ONCE, before the call | 'Spam Spam Spam Spam ' |
| bruce | refers to the finished string | printed twice |
| math.cos(math.pi) | evaluated once, before the call | -1.0 |
Identify the argument.
Why: It is an expression, and the same rules of composition that apply to built-in functions also apply to programmer-defined functions.
Note when it runs.
Why: The argument is evaluated before the function is called, so 'Spam ' * 4 is only evaluated once even though bruce is used twice inside.
Check the consequence.
Why: The two printed lines are identical, because they are two printings of one value rather than two evaluations of one expression.
Figure (svg): A diagram showing an argument expression being evaluated to a value, which is then bound to the parameter and used twice inside the function
Both work, and in each case the argument expression is evaluated once, before the call. The body sees a finished value and has no access to the expression that produced it.
Verify: Reason about what you would see if the expression were evaluated per use.
Why: If the expression ran once per mention of bruce, a random or time-dependent argument would print two different values. It does not, which is observable evidence for the once-before-the-call rule rather than an assertion of it.
Trap
Having written def print_twice(bruce), a student believes they must create a variable called bruce before they can call it.
Assume the two names are connected
Why: They appear in the same call, and one does supply the other's value, so a connection is a natural inference.
This leads to renaming variables at the call site to match parameters, which is unnecessary, and to confusion whenever the same function is called with two differently named variables.
The names are entirely independent. Only the VALUE travels.
Name the caller's variable for what it means there
Why: michael = 'Eric, the half a bee.' is named for the caller's purposes.
Name the parameter for what it means inside the function
Why: bruce is the function's own name for whatever it was given.
The book states it directly: the name of the variable passed as an argument has nothing to do with the name of the parameter. It does not matter what the value was called back home; here in print_twice, we call everybody bruce.
Matching
Two words that beginners routinely swap. Fix them here, once.
Match the pairs
Why: The clean way to remember it: the parameter is written once, in the definition; the argument is written at every call, and can be different every time. One function with one parameter can be called with a thousand different arguments, which is the whole reason parameters exist.
Fill the middle
One blank in the header, one in the body. They must agree with each other and with nothing else.
Fill in the blanks
def shout(message):
print(message)
shout('hello')
Why: Any legal name would do for the parameter, as long as the body uses the same one — the two blanks must match each other. Note what they need NOT match: the argument at the call site is the literal 'hello', which has no name at all, and that is perfectly fine. A parameter is the function's private name for whatever arrives.
Explain it
This is the distinction most worth being able to explain, because so much documentation assumes it.
Discussion prompt
In two sentences, explain to somebody the difference between a parameter and an argument, using print_twice as your example. Then give them a one-line test they could run to convince themselves the names are independent.
Hint: The test should involve calling the function with a variable that has a different name.
Answer:
Say: the parameter is the name the function uses for whatever it is given, written once in the header. The argument is the actual value handed over at the call, written fresh every time you call it.
The test: make a variable with any name at all — x = 'hi' — and call print_twice(x). It works, which proves the caller's name is irrelevant.
A stronger version of the test is to call it twice with two differently named variables. Both work, and no single name could have satisfied both, so the independence is not a coincidence of the first example.
Comparison
Fill the blanks. Almost every confusion in this lesson is a mix-up between these two columns.
Comparison matrix
| Question | The definition | The call |
|---|---|---|
| What does it do? | creates a function object and names it | runs the statements in the body |
| Does it produce output? | no, never | yes, if the body prints anything |
| How is it written? | def, a name, parentheses, a colon, an indented body | the name, then parentheses |
| When are the body's names looked up? | not at all | when the body runs, at call time |
The bottom row is the one that surprises people, and it is the reason a broken function can sit in a file for months without anybody noticing.
Pattern
Six steps, and the last two are the ones beginners skip.
Step 6 is not a formality. A definition with a typo in its body is accepted silently and fails only when called, so an uncalled function is an untested function.
Python documentation — More Control Flow Tools More Control Flow Tools
Check
Two events, and only one of them produces anything.
def show():
print('hi')| Lines | What happens | Note |
|---|---|---|
| 1-2 | the definition executes | a function object is created |
| output | none | the body has not run |
| to see 'hi' | call show() | then the body runs |
Check your understanding
This is the entire content of a script. What does it print?
Answer: B
Why: The definition creates a function object and binds the name show to it. The statements inside the function do not run until the function is called, and nothing calls it, so the print statement never executes. A definition generates no output — the silence is correct rather than a symptom.
Check
Follow the flow, not the page.
def f():
print('B')
print('A')
f()
print('C')| Line | What runs | Output |
|---|---|---|
| 4 | print('A') | A |
| 5 | detour into f | B |
| 6 | return and continue | C |
Check your understanding
In what order does this script print A, B and C?
Answer: B
Why: The definition runs silently, so execution effectively starts at line 4 and prints A. The call on line 5 is a detour into the body, which prints B, and then the flow comes back to pick up where it left off — line 6, which prints C. Following the flow gives A, B, C.
Check
Only the value crosses into the function.
def double(n):
print(n * 2)
count = 5
double(count)| Line | What happens | State or output |
|---|---|---|
| count = 5 | a name in __main__ | count -> 5 |
| double(count) | the value 5 is passed | n -> 5 |
| print(n * 2) | inside the function | 10 |
Check your understanding
Which of these is true about this program?
Answer: B
Why: The call evaluates the argument — the expression count, which is worth 5 — and assigns that value to the parameter n. The names are independent: n exists only inside the function, count only outside, and only the value 5 travelled between them. Doubling it prints 10.
Real world
Defining something once and invoking it by name is not a programming idea.
Discussion prompt
Find something outside programming that is defined once and then invoked by name many times, where the definition itself does nothing until invoked — a recipe, a legal procedure, a piece of choreography, a keyboard shortcut. What plays the role of the argument?
Hint: A recipe that says for any quantity of flour has a parameter.
Answer:
A recipe is the clearest case. Writing it down does nothing; cooking it is the call. Scale to n servings is a parameter, and the number of guests is the argument.
Legal procedure works too: a defined process is invoked with a particular case as its argument, and the process is written in terms of the applicant rather than a specific person's name — which is exactly the parameter-versus-argument distinction.
In both cases the definition is written once, in general terms, and the specific values arrive at invocation. That is the whole design pattern, and functions are the programming instance of it.
Commit first
Answer, then rate your confidence. This one is about when Python checks things.
Predict first
A script defines a function whose body calls a function that does not exist anywhere. The script never calls the defined function. What happens when you run it?
Correct: Nothing — it runs cleanly, because the body is never executed and its names are never looked up.
Why: A definition creates a function object without examining what the body refers to. Names inside a body are looked up when the body runs, and this body never runs. The practical consequence is important and slightly alarming: a Python file can contain thoroughly broken functions and still run without complaint, which is why calling every function you write at least once is not optional. If you predicted an immediate error, you were expecting a compiler-style check that Python does not perform.
Explain it
The definition-versus-call distinction is the whole lesson, and it is best tested by explaining it.
Discussion prompt
A classmate has written a function with three print statements in it, run the file, and got no output. They are sure the function is wrong. Explain what has probably happened and what one line would fix it — and say how you knew without seeing their code.
Hint: This is the same diagnostic shape as the script-mode silence from lesson 2a.
Answer:
Say: a definition creates the function and runs nothing, so a file that only defines functions produces no output. They almost certainly never called it.
The fix is one line at the bottom: the function's name followed by parentheses. Nothing inside the function needs to change.
How you knew without seeing it: the symptom is total silence from code that obviously contains print statements, and there are only two common causes — no print at all, or no call. Since they told you there are three prints, it is the call. Being able to narrow it that far from a symptom is exactly what the error taxonomy from lesson 2b is for.
Exit ticket
One honest answer. It decides what the next lesson opens with.
Predict first
Which of these is still least solid for you?
Correct: Whichever you picked is the right answer — this one is for you, not for a mark.
Why: The syntax settles within a handful of functions and your editor helps. The definition-versus-call distinction is the conceptual core and is worth revisiting until it is automatic, because lesson 3c's stack diagrams assume it. Flow tracing is a skill that keeps improving and pays off most in chapter 5, where recursion makes it essential. And the parameter-argument distinction is the one that quietly blocks progress if left fuzzy — it is why chapter 6's fruitful functions make sense, and why chapter 10's list arguments are surprising.
Connect it up
One page, no code, from memory.
Draw it
Draw a timeline running left to right for a script that defines two functions and then calls one of them. Mark on it: when each function object is created, when the flow detours, when it returns, and when any output appears. Then, above the timeline, mark the one moment at which the names inside a body are looked up — and write one sentence on why that moment is later than most people expect.
Recap
Three pages, and you can write functions of your own.
| If you remember one thing | It is this |
|---|---|
| From the syntax | The colon ends the header and the indentation is the body. Both are required. |
| From definitions | A definition runs nothing and checks nothing. An uncalled function is an untested function. |
| From the flow | A call is a detour that comes back to the very next line. |
| From parameters | Only the value travels. What it was called back home is nobody's business inside the function. |
The next lesson finishes chapter 3: what happens to a function's variables when it returns, how to draw a stack diagram, how to read a traceback, and the difference between a function that returns a result and one that merely does something.
Think Python, 2nd edition — Allen B. Downey §3.4-3.7, pp. 19-21 — everything on these slides traces back here
Want this taught 1-on-1? Alexander tutors Python — $55/session, free consultation.