Parameters and Return Values
A photocopier has a slot for paper going in and a tray for copies coming out. Know what goes in and what comes out, and you can use it without opening it up.
In Writing Functions, you wrote functions that took a value in and functions that handed a value back. This lesson looks closely at both ends: how to pass several values, what the function actually receives, and how to design a function whose inputs and outputs make sense.
A machine with a slot and a tray
Think of a function as a machine on a counter. There's a slot where you feed things in, and a tray where the result comes out.
- The parameters are the slot. They say what the machine needs.
- The return value is the tray. It says what the machine gives back.
You don't need to know how the machine works inside. As long as you know what goes in and what comes out, you can use it.
Parameters and arguments
Two words that sound alike and mean slightly different things:
def add(a, b): # a and b are parameters
return a + b
total = add(5, 3) # 5 and 3 are arguments
print(total)8- Parameters are the names listed in the function's definition:
aandb. - Arguments are the actual values you pass in when you call it:
5and3.
When the function is called, each argument is matched to its parameter, in order: a gets 5, and b gets 3. People mix these two words up all the time, and nobody will be confused if you do. But error messages use them precisely, so it helps to know the difference.
Several parameters
Separate parameters with commas:
def print_score(name, score, max_score):
print(f"{name}: {score} / {max_score}")
print_score("Maria", 47, 50)Maria: 47 / 50Arguments are matched to parameters by position. "Maria" goes into name because it's first. Mix up the order, and Python quietly uses the wrong values, since it has no way to know:
print_score("Maria", 50, 47)Maria: 50 / 47The number of arguments has to match, too. Leave one out, and Python tells you exactly which:
print_score("Maria", 47) # error: TypeError: print_score() missing 1 required positional argument: 'max_score'In Default and Keyword Arguments, you'll see how to name arguments so their order doesn't matter, and how to make some of them optional.
Returning several values
Sometimes a function naturally has more than one answer. Dividing up cookies gives you both how many each friend gets and how many are left over. Python lets you return several values, separated by commas, and unpack them into several variables in one line:
def share(cookies, friends):
each = cookies // friends
left = cookies % friends
return each, left
per_friend, leftover = share(20, 6)
print(f"{per_friend} each, {leftover} left over")3 each, 2 left overThis uses the same trick as x, y = 3, 4 from Variables and Naming. (Behind the scenes, the function returns a tuple, which you'll meet in Tuples.)
What happens to what you pass in?
Here's something that surprises people. What does this print?
def add_bonus(points):
points = points + 10
print("Inside the function:", points)
score = 70
add_bonus(score)
print("Outside the function:", score)Inside the function: 80
Outside the function: 70When you call add_bonus(score), the parameter points becomes a second name tag stuck on the same value, 70. Then points = points + 10 moves the points tag to a brand-new value, 80. The score tag outside never moves, so it still says 70.
If you want the change to stick, return the new value, and store it:
def add_bonus(points):
return points + 10
score = 70
score = add_bonus(score)
print(score)80That's the clean, predictable way: data goes in through parameters, and results come out through return.
(Later, in Lists, you'll see one important twist. A list can be changed in place, without moving any name tag, so a function that adds an item to a list you passed in really does change your list. For numbers, strings, and booleans, which can never be changed in place, what you've learned here is the whole story.)
Leaving early with return
Because return ends the function immediately, you can use it to leave early. This is called an early return, and it often makes code simpler than a deep if/else:
def letter_grade(score):
if score < 0 or score > 100:
return "Invalid"
if score >= 90:
return "A"
if score >= 80:
return "B"
return "C or below"
print(letter_grade(105))
print(letter_grade(84))Invalid
BThe invalid case is handled first and gets out of the way, so the rest of the function only deals with good scores.
Type hints
You'll often see Python functions written like this:
def average(a: float, b: float) -> float:
return (a + b) / 2
print(average(3, 4))3.5The : float after each parameter and the -> float after the parentheses are type hints. They say what types the function expects and gives back. Python itself doesn't enforce them, but code editors use them to warn you about mistakes, and they make a function's slot and tray easy to see at a glance. You don't need them yet, but now you'll recognize them.
Designing good functions
- Take in what you need, nothing more. A function that calculates an average needs the scores, not the student's name.
- Return results instead of printing them, when the caller might want to do something else with the answer.
- Keep the parameter list short. Three or four is plenty. If you need seven, some of them probably belong together, maybe in a dictionary or an object.
- Name parameters clearly.
line_total(price, quantity)explains itself.line_total(p, q)doesn't.
Try it
This program runs a small cafeteria checkout. Watch which functions return values, which only print, and what happens to budget when it's passed into a function. Predict the output.
Running Python here
Running Python right in the browser is coming to Syntaxia soon. For now, you can read and edit the code here. If you have Python installed on your computer (see Setting Up), save it as main.py and run it with python main.py (or python3 main.py on macOS and Linux).
Check your prediction
Adobo x2 130.00
Juice x3 60.00
Total 190.00
Budget after spend(): 200
Budget after remaining(): 10
Split 4 ways: 47 each, plus 2 extraspend only moved its own money name tag, so budget outside was still 200. remaining returned the new value, and the program stored it, so that change stuck. split_bill returned two values, unpacked into each and extra.
Try it yourself
- Add a third item, rice at 15 pesos with quantity 2, and include it in the total.
- Delete the
spendfunction and the lines that use it. Why was it useless? - Write a function
apply_discount(amount, percent)that returns the amount after a discount, and use it to take 10 percent off the total before subtracting it from the budget.
Check your understanding
Up next
Sometimes you want a parameter to be optional, like a greeting that says "Hello" unless you ask for something else. Or you want to name arguments so their order stops mattering. That's Default and Keyword Arguments.
