Defining functions¶
Goal: name a block of code so you can run it whenever you like, with different inputs each time, and get a result back.
Why this matters¶
Here is a program that welcomes three people with a banner:
print("=" * 30)
print("Welcome, Ada!")
print("=" * 30)
print("=" * 30)
print("Welcome, Grace!")
print("=" * 30)
print("=" * 30)
print("Welcome, Linus!")
print("=" * 30)
It works, but the same three lines are copied three times. Now suppose you want the banner to use - instead of =.
You have to change three places, and if you miss one, the program is inconsistent. With ten banners it gets worse.
Copying code is the problem. A function is the fix: you write the block once, give it a name, and run it by name as many times as you like.
Your first function¶
def print_banner():
print("=" * 30)
print("Welcome!")
print("=" * 30)
print_banner()
print("Some other work happens here.")
print_banner()
==============================
Welcome!
==============================
Some other work happens here.
==============================
Welcome!
==============================
The first four lines define the function. def is short for define, then comes the name you chose,
then empty parentheses, then a colon. The indented lines below are the function's body, exactly like the body of an if or a loop.
Defining a function does not run it. Python reads the definition, remembers it under the name print_banner, and moves on.
The body only runs when you call the function by writing its name followed by parentheses: print_banner().
Each call runs the whole body from the top.
You have been calling functions since lesson one. print(), input(), len(), int(), and random.randint() are all functions
that someone else defined. The only new thing here is that you are the one writing the definition.
Function names follow the same rules as variable names: lowercase, words joined with underscores. A good name says what
the function does, so it usually starts with a verb: print_banner, calculate_total, ask_for_number.
Parameters: giving a function input¶
The banner above always says Welcome!. To make each call different, give the function a parameter,
a variable name inside the parentheses that receives a value on every call:
def print_banner(name):
print("=" * 30)
print(f"Welcome, {name}!")
print("=" * 30)
print_banner("Ada")
print_banner("Grace")
print_banner("Linus")
==============================
Welcome, Ada!
==============================
==============================
Welcome, Grace!
==============================
==============================
Welcome, Linus!
==============================
name is the parameter. When you call print_banner("Ada"), Python sets name = "Ada" and runs the body.
The value you pass in, "Ada", is called an argument. Parameter is the name in the definition, argument is the value
in the call. People mix the two words up constantly, and it rarely matters.
This is the same output as the copied version at the top of the lesson, from a third of the code. Changing the banner character is now a one-line edit.
A function can take several parameters, separated by commas. The arguments are matched up in order:
def print_banner(name, width):
print("=" * width)
print(f"Welcome, {name}!")
print("=" * width)
print_banner("Ada", 20)
print_banner("Grace", 40)
====================
Welcome, Ada!
====================
========================================
Welcome, Grace!
========================================
print_banner("Ada", 20) sets name to "Ada" and width to 20. Swap the arguments to print_banner(20, "Ada")
and width becomes "Ada", so the first line of the body tries "=" * "Ada" and crashes with a TypeError.
Order matters. Keep the arguments in the order the definition lists them.
Default values¶
If most calls would pass the same value, give the parameter a default in the definition. Callers can then leave it out:
def print_banner(name, width=30):
print("=" * width)
print(f"Welcome, {name}!")
print("=" * width)
print_banner("Ada")
print_banner("Grace", 10)
==============================
Welcome, Ada!
==============================
==========
Welcome, Grace!
==========
width=30 means use 30 unless the caller says otherwise. You have used this already: print() puts a newline
at the end by default, and round(x) rounds to zero decimal places unless you pass a second argument.
Parameters with defaults must come after the ones without.
Return: getting a result back¶
So far the banner function does something. Many functions instead work something out and hand the answer back
with return:
def add_tax(price):
return price * 1.2
total = add_tax(100)
print(total)
print(add_tax(50) + add_tax(25))
return price * 1.2 ends the function and sends that value back to wherever the call was made. The call
add_tax(100) then becomes 120.0, and you can do anything with it that you could do with the number itself:
store it in a variable, print it, or add it to another call. len() and int() work this way, which is why you write
length = len(word).
When Python hits return, the function stops immediately. Any lines after it inside the body never run.
return is not print¶
This is the most important idea in the lesson, and the one beginners struggle with most:
def double_print(n):
print(n * 2)
def double_return(n):
return n * 2
result = double_print(5)
print(result)
result = double_return(5)
print(result)
double_print(5) shows 10 on the screen, but hands nothing back, so result becomes None, the same nothing value
that .append() returns. double_return(5) shows nothing on its own, but hands 10 back, so result is 10 and the
print outside the function shows it.
The rule of thumb: a function should usually return its answer and let the caller decide whether to print it.
A function that prints is a dead end, because you cannot do anything else with what it printed.
The banner function is fine printing, because showing a banner is its job. A function that calculates should return.
Variables inside a function are private¶
Variables created inside a function exist only while that function is running:
def calculate_area(width, height):
area = width * height
return area
room = calculate_area(4, 5)
print(room)
print(area)
20
Traceback (most recent call last):
File "scope.py", line 7, in <module>
print(area)
^^^^
NameError: name 'area' is not defined
area was created inside calculate_area, so it disappears when the function returns. Outside, it does not exist.
This is called scope, and it is a feature: functions cannot accidentally overwrite each other's variables,
so you can reuse simple names like total or i in every function without worrying.
The way to get a value out of a function is return, as calculate_area does. room holds the returned value,
and that works fine. Parameters are private too: width and height only exist inside the function.
Try it¶
Write a function describe(name, age) that returns a string such as Ada is 36 years old. Call it three times
with different people and print each result. Then give age a default value and call it with just a name.
Common mistakes¶
The function does nothing
You defined it but never called it. A definition on its own runs nothing. Add my_function() below the definition.
TypeError: greet() missing 1 required positional argument: 'name'
The definition has a parameter but the call passed no argument. Write greet("Ada"), not greet().
TypeError: greet() takes 1 positional argument but 2 were given
The opposite: more arguments than parameters. Check the definition and the call match.
The result is None
The function prints instead of returning, or has no return at all, or the return is inside an if that was not taken.
Make sure every path through the function ends in a return.
NameError: name 'total' is not defined
You are using a variable outside the function that was created inside it. Return the value instead, and store it when you call the function.
The code after return never runs
That is expected. return ends the function on the spot. Move the lines above the return if they need to run.
Exercises¶
- Greet. Write
greet(name)that prints a friendly greeting. Call it with two fixed names and once with a name frominput(). - Even check. Write
is_even(number)that returnsTruefor even numbers andFalseotherwise. Use it in a loop to print the even numbers from 1 to 10. A function that returnsTrueorFalseusually gets a name starting withis_. - Average. Write
average(numbers)that takes a list and returns its average. Make it return0for an empty list instead of crashing. Test it with three different lists. - Tip calculator, again. In Module 1 you wrote a tip calculator. Rewrite it around a function
calculate_tip(bill, percent=15)that returns the tip rounded to two decimal places. Then use the same function to also show a 20% tip.
Solution 1
def greet(name):
print(f"Hello, {name}! Nice to meet you.")
greet("Ada")
greet("Grace")
greet(input("What is your name? "))
The last call passes the result of input() straight in as the argument. Functions calling functions is normal.
Solution 2
def is_even(number):
return number % 2 == 0
print(is_even(4))
print(is_even(7))
for n in range(1, 11):
if is_even(n):
print(f"{n} is even")
number % 2 == 0 is already True or False, so you return it directly. There is no need for
if number % 2 == 0: return True else: return False, though that works too.
Solution 3
def average(numbers):
if len(numbers) == 0:
return 0
return sum(numbers) / len(numbers)
print(average([82, 95, 77, 60]))
print(average([10, 20]))
print(average([]))
Two return statements, but only one runs on any given call. If the list is empty, the first return ends the
function before the division can happen.
Solution 4
def calculate_tip(bill, percent=15):
return round(bill * percent / 100, 2)
bill = float(input("Bill amount: "))
tip = calculate_tip(bill)
print(f"Tip: {tip}")
print(f"Total: {round(bill + tip, 2)}")
print(f"A generous 20% tip would be {calculate_tip(bill, 20)}")
The function returns rather than prints, which is what makes the second use possible. The default percent=15
keeps the common case short.
Summary¶
def name(parameters):defines a function. The body runs only when you callname(arguments).- Parameters are the names in the definition. Arguments are the values passed in a call, matched by position.
parameter=valuein the definition gives a default, so callers can leave it out.return valuesends a result back and ends the function. Store or use the result at the call.- Printing inside a function shows something. Returning gives something back. Calculating functions should return.
- Variables created inside a function are private to it. Use
returnto get values out.