Unit 06 · lesson
Parameters, Arguments, and Return Values
Core path: 30 minutes
How can one function work with different data instead of repeating the same fixed behavior?
Our first functions mostly behaved the same every time they were called.
def greet():
print("Hello, developer.")
Useful, but limited.
Functions become much more powerful when the caller can provide data.
A parameter creates a named input boundary
def greet(name):
print(f"Hello, {name}.")
Inside the function definition, name is a parameter.
It is a local name that will receive a value when the function is called.
Now:
greet("Maya")
greet("Jordan")
uses the same behavior with different arguments.
Trace the first call:
caller has value "Maya"
↓
greet("Maya")
↓
parameter name refers to "Maya"
↓
function body uses name
↓
prints "Hello, Maya."
The argument is the value supplied by the caller.
The parameter is the name used inside the function to receive it.
Position matters unless you say otherwise
def show_score(player_name, score):
print(f"{player_name}: {score} points")
This call matches the parameter order:
show_score("Nova", 850)
This one is valid Python too:
show_score(850, "Nova")
But now the values are bound differently:
player_name = 850
score = "Nova"
and the output becomes nonsense for the intended meaning.
That is an important theme in programming: syntax can be valid while the data is semantically wrong.
Keyword arguments can make the mapping explicit
Python also supports:
show_score(player_name="Nova", score=850)
Now the argument-to-parameter relationship is named directly.
You do not need to convert every call into keyword arguments. Use them when they improve clarity, especially when several parameters have similar-looking values.
return sends a value back to the caller
Consider:
def calculate_damage(base, multiplier):
damage = base * multiplier
return damage
Then:
result = calculate_damage(50, 2)
print(result)
The call does more than execute a block. It produces a value that the caller can store or use.
Conceptually:
caller supplies arguments
↓
parameters receive values
↓
function calculates
↓
return sends result back
↓
caller receives returned value
Change the arguments. Follow the returned value.
The execution path stays the same, but the data moving through each stage changes with the arguments you supply.
Change base and multiplier. Before reading the result, predict the returned value and trace where each number appears inside the function.
Change the values and watch the code, trace, and model update together.
def calculate_damage(base, multiplier):
damage = base * multiplier
return damage
result = calculate_damage(50, 2)
print(result)- arguments: 50, 2
- parameters: base = 50, multiplier = 2
- damage = 50 × 2 = 100
- return 100 → result
Current model for base = 50, multiplier = 2. Active connections show the path or transfer currently being demonstrated.
Drag nodes to inspect the relationships. Motion shows the active path; the plain background keeps attention on the relationships instead of graph-paper decoration.
View static diagram
Change the live base and multiplier values.
Watch the labels update through the fixed pipeline.
Unlike the Week 4 branch model, the path itself does not change here. The data moving through the path changes.
Now execute the same boundary in a smaller runnable example:
Run the code to see output.
Change the return expression and observe how the caller receives a value from the function.
Change one argument and then change the return expression. The caller should only observe the value that crosses the function boundary, not the function's internal local names.
print() and return solve different jobs
This function displays a value:
def add_numbers(a, b):
print(a + b)
Then:
result = add_numbers(10, 5)
print(result)
produces something like:
15
None
The function displayed 15, but it did not return 15.
Without an explicit useful return value, Python functions return None.
Now compare:
def add_numbers(a, b):
return a + b
The caller can decide what happens next:
result = add_numbers(10, 5)
print(result)
or:
if add_numbers(10, 5) > 12:
print("Large result")
or:
final = add_numbers(10, 5) * 2
Returning a value makes the function composable.
A returned value can feed another function
def calculate_average(score1, score2, score3):
return (score1 + score2 + score3) / 3
def determine_status(average):
if average >= 70:
return "PASS"
return "REVIEW"
Then:
average = calculate_average(80, 90, 100)
status = determine_status(average)
print(status)
Data flows through two function boundaries:
scores
↓
calculate_average()
↓ returned average
determine_status()
↓ returned label
print()
The functions do not have to know everything about each other. They agree on the values crossing the boundary.
return also ends the function call
Consider:
def classify(score):
if score >= 90:
return "A"
return "OTHER"
print("This never runs")
Once Python executes return, control leaves that function immediately.
Any later statement on that execution path is unreachable.
This makes early-return patterns possible later, but it also means misplaced code after return can silently become dead code.
Trace one function call precisely
def calculate_total(price, quantity):
subtotal = price * quantity
tax = subtotal * 0.06
return subtotal + tax
amount = calculate_total(10.0, 3)
print(amount)
Trace:
price = 10.0
quantity = 3
subtotal = 30.0
tax = 1.8
return 31.8
amount = 31.8
Then change quantity to 5 and predict every changing value before running.
Before Lesson 3
You should be able to distinguish:
argument value supplied by caller
parameter local name receiving that value
local variable name created inside function
return value data sent back to caller
printed output visible side effect
Those differences are what let functions become clean boundaries instead of little code containers.
Vocabulary lab
Flip the idea, not just the card
Explain the term before you reveal the back. Then compare your explanation with the definition, example, and warning.
Read all terms without animation
- Parameter
- A local name in a function definition that receives an argument value when the function is called. Example: name in def greet(name): Do not confuse it with: The argument supplied by the caller.
- Argument
- A value or expression supplied to a function call. Example: 'Maya' in greet('Maya'). Do not confuse it with: The parameter name inside the function definition.
- Return Value
- A value a function sends back to its caller using return. Example: return base * multiplier sends the calculated result back. Do not confuse it with: Text printed to the terminal as a side effect.
- None
- Python's special value commonly returned when a function finishes without returning another explicit value. Example: A function that only print()s usually returns None. Do not confuse it with: An empty string or the number zero.
- Function Composition
- Using the returned result of one function as input to another part of the program or another function. Example: determine_status(calculate_average(...)). Do not confuse it with: Copying the implementation of one function inside another.