Functions
Defining reusable blocks of code: parameters and arguments, return values, defaults, keywords and scope.
Why functions
A function is a named block of code that performs one task. You define it once and then call it wherever you need that task done. Functions give you three things: you do not repeat yourself, you can give a piece of logic a clear name, and you can test and fix it in one place.
You have been using functions from the start:
print(), len() and input()
are built-in functions. This page is about writing your own.
Defining a function
A definition starts with the keyword def, then the
function's name, parentheses and a colon. The indented block below
it is the function's body.
def greet():
print("Good morning!")
print("Coffee is ready.")
greet()
greet()
Good morning! Coffee is ready. Good morning! Coffee is ready.
The def statement itself runs nothing: it creates the
function and binds it to the name greet. The body only
runs when you call the function by writing its name
followed by parentheses. Without the parentheses,
greet is just a reference to the function object.
Define before you call
Python runs a script from top to bottom, so a function must be
defined before the line that calls it is executed. Calling it
earlier fails with a NameError:
show_total()
def show_total():
print("Total: 42")
NameError: name 'show_total' is not defined
Parameters and arguments
To make a function work on different data, give it inputs. A parameter is a name listed between the parentheses in the definition. An argument is the actual value you pass in a call. When the function runs, each parameter is bound to its argument, and behaves like a variable inside the body.
def greet(name, drink): # name and drink are parameters
print(f"Good morning, {name}! Your {drink} is ready.")
greet("Ada", "tea") # "Ada" and "tea" are arguments
greet("Linus", "coffee")
Good morning, Ada! Your tea is ready. Good morning, Linus! Your coffee is ready.
The number of arguments must fit the parameters. Calling
greet("Ada") fails with
TypeError: greet() missing 1 required positional argument:
'drink'.
Positional and keyword arguments
A positional argument is matched to a parameter by
its position: the first argument goes to the first parameter, and so
on. A keyword argument is
passed as name=value and matched by the parameter's
name, so its position does not matter. Keyword arguments make calls
easier to read, especially for numbers and truth values.
def price_with_tax(price, rate):
return round(price * (1 + rate), 2)
print(price_with_tax(10.0, 0.21)) # positional
print(price_with_tax(rate=0.09, price=10.0)) # keyword, any order
print(price_with_tax(10.0, rate=0.21)) # mixed
12.1 10.9 12.1
In a call, all positional arguments must come before all keyword arguments, and each parameter may receive only one value:
price_with_tax(rate=0.21, 10.0) # SyntaxError: positional argument follows keyword argument
price_with_tax(10.0, price=12.0) # TypeError: got multiple values for argument 'price'
Default arguments
A parameter can have a
default argument: a value
written in the definition with =, used when the call
does not supply one. That makes the argument optional.
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet("Ada")
greet("Ada", "Welcome back")
greet("Ada", greeting="Hi")
Hello, Ada! Welcome back, Ada! Hi, Ada!
In the definition, parameters with a default must come after the
parameters without one.
def greet(greeting="Hello", name): is a
SyntaxError.
def add_item(item, basket=[]): # the trap
basket.append(item)
return basket
print(add_item("apple"))
print(add_item("bread")) # the old apple is still there!
def add_item_safely(item, basket=None):
if basket is None:
basket = [] # a new list on every call
basket.append(item)
return basket
print(add_item_safely("apple"))
print(add_item_safely("bread"))
['apple'] ['apple', 'bread'] ['apple'] ['bread']
The fix is the idiom above: use None as the default and
create the new object inside the body.
*args and **kwargs
Sometimes a function should accept any number of arguments. A
parameter written with one star, conventionally
*args, collects all extra positional arguments into a
tuple. A parameter with two
stars, conventionally **kwargs, collects all extra
keyword arguments into a
dictionary. The names
args and kwargs are only a convention; the
stars do the work.
def total(*prices):
print(prices)
return sum(prices)
print(total(2.50, 3.20, 4.75))
print(total())
def describe(name, **details):
print(name, details)
describe("Oslo", country="Norway", population=709_000)
(2.5, 3.2, 4.75)
10.45
()
0
Oslo {'country': 'Norway', 'population': 709000}
The stars also work the other way round, in a call: *
unpacks a sequence into positional arguments and
** unpacks a dictionary into keyword arguments.
def price_with_tax(price, rate):
return round(price * (1 + rate), 2)
values = [10.0, 0.21]
options = {"price": 20.0, "rate": 0.09}
print(price_with_tax(*values))
print(price_with_tax(**options))
12.1 21.8
Keyword-only and positional-only parameters
Two markers in a parameter list restrict how arguments may be
passed. Parameters after a bare * (or after
*args) are keyword-only: they can only
be passed by name. Parameters before a / are
positional-only: they cannot be passed by name.
Library functions use these to keep calls readable and to leave
parameter names free to change.
def convert(celsius, /, *, decimals=1):
return round(celsius * 9 / 5 + 32, decimals)
print(convert(21.5))
print(convert(21.5, decimals=0))
70.7 71.0
Here convert(21.5, 0) is a
TypeError because decimals is
keyword-only, and convert(celsius=21.5) is a
TypeError because celsius is
positional-only.
Return values
The return statement ends the function immediately and
hands a value back to the caller. That value is the function's
return value: the call
expression evaluates to it, so you can store it, print it or use it
in a larger expression.
def area(width, height):
return width * height
room = area(4, 3.5)
print(room)
print(area(2, 2) + area(1, 3))
14.0 7
A function without return returns None
Every call returns something. If the body ends without reaching a
return statement, or runs a bare return,
the function returns None. Printing a value is not the
same as returning it: print() shows text on the screen,
but the caller receives nothing it can use.
def show_area(width, height):
print(width * height) # prints, but does not return
result = show_area(4, 3)
print(result)
12 None
Returning several values
A function returns exactly one object, but that object can be a
tuple. return a, b builds the tuple
(a, b), and the caller can unpack it straight into
separate names.
def min_max(temperatures):
return min(temperatures), max(temperatures)
week = [14.5, 17.0, 12.5, 19.5, 16.0]
low, high = min_max(week)
print(low, high)
print(min_max([3, 1, 2]))
12.5 19.5 (1, 3)
Scope
A name's scope is the part of the program where that name can be used. Every call of a function gets its own, fresh namespace for the names it creates.
Local and global variables
A local variable is a name
assigned inside a function, including its parameters. Each call gets
a fresh set of local variables, which cannot be seen from outside
the function. A
global variable is a name
assigned at the top level of a module (a .py file);
every function in that module can read it.
vat_rate = 0.21 # global
def gross(net):
tax = net * vat_rate # tax and net are local; vat_rate is read from global
return net + tax
print(gross(100))
print(vat_rate)
print("tax" in globals()) # tax does not exist outside the function
121.0 0.21 False
The LEGB rule
When Python meets a name, it looks it up in four scopes, in this order, and uses the first match:
- Local — names assigned in the current function.
- Enclosing — names in any function that contains the current one (for nested functions).
- Global — names at the top level of the module.
-
Built-in — names Python provides, such as
lenandprint.
If none of the four has the name, you get a
NameError.
The global and nonlocal keywords
The scope of a name is decided when the function is compiled, not while it runs: if a function assigns to a name anywhere in its body, that name is local in the whole body. So a function can read a global variable, but an assignment creates a new local one instead of changing the global. Reading it before that assignment fails:
visitors = 0
def welcome():
visitors = visitors + 1 # visitors is local here, and not yet set
welcome()
UnboundLocalError: cannot access local variable 'visitors' where it is not associated with a value
The statement global name tells Python that the name in
this function refers to the global variable. The statement
nonlocal name does the same for a variable of an
enclosing function.
visitors = 0
def welcome():
global visitors
visitors = visitors + 1
welcome()
welcome()
print(visitors)
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = make_counter()
print(counter(), counter(), counter())
2 1 2 3
Shadowing
A local name hides a global or built-in name with the same spelling. This is called shadowing. Inside the function the local one wins; outside, nothing changes.
city = "Oslo"
def show():
city = "Lisbon" # a new local name that shadows the global one
print("inside:", city)
show()
print("outside:", city)
inside: Lisbon outside: Oslo
Recursion
Recursion means that a function calls itself to solve a smaller version of the same problem. Every recursive function needs a base case: an input it answers directly, without calling itself. Each recursive call must move closer to that base case.
The factorial of n (written n!) is the product 1 × 2 × … × n. It is defined recursively: 1! = 1, and n! = n × (n − 1)!.
def factorial(n):
if n <= 1: # base case
return 1
return n * factorial(n - 1) # recursive case: a smaller problem
print(factorial(5))
print(factorial(1))
120 1
factorial(5) calls factorial(4), which
calls factorial(3), down to factorial(1),
which returns 1. The waiting calls then finish in reverse order: 2 ×
1, 3 × 2, 4 × 6, 5 × 24.
Every call that has not finished yet takes up memory. Python limits
the depth of nested calls (1000 by default) and raises a
RecursionError when a program goes deeper, which is
what happens when the base case is missing or never reached:
def countdown(n):
return countdown(n - 1) # no base case: never stops
countdown(3)
RecursionError: maximum recursion depth exceeded
Functions are objects
In Python a function is an object like any other. You can assign it
to another name, store it in a list, and pass it as an argument to
another function. Many built-ins use this: sorted(),
min() and max() accept a
key function that turns each item into the value to
compare.
def last_letter(word):
return word[-1]
cities = ["Rotterdam", "Oslo", "Lisbon", "Rome"]
print(sorted(cities, key=len)) # pass the function, do not call it
print(sorted(cities, key=last_letter))
measure = len # another name for the same function
print(measure("Oslo"))
['Oslo', 'Rome', 'Lisbon', 'Rotterdam'] ['Rome', 'Rotterdam', 'Lisbon', 'Oslo'] 4
Note key=len, not key=len(): you pass the
function itself, and sorted() calls it once per item.
Lambda expressions
A lambda expression creates a small,
anonymous function in one line:
lambda parameters: expression. Its body is a single
expression, whose value is returned automatically. Lambdas are handy
for short key functions that you need only once.
products = [("tea", 2.50), ("cake", 4.75), ("coffee", 3.20)]
print(sorted(products, key=lambda item: item[1]))
print(max(products, key=lambda item: item[1]))
square = lambda x: x ** 2
print(square(7))
[('tea', 2.5), ('coffee', 3.2), ('cake', 4.75)]
('cake', 4.75)
49
Assigning a lambda to a name, as with square above,
works but is discouraged by the style guide: use def
when a function deserves a name.
Docstrings
A string literal as the first statement of a function body is its
docstring: documentation that tools and
help() can show. It describes what the function does,
not how. The conventions are covered in
Code Style and Good Habits.
def celsius_to_fahrenheit(celsius):
"""Convert a temperature from degrees Celsius to Fahrenheit."""
return celsius * 9 / 5 + 32
print(celsius_to_fahrenheit.__doc__)
print(celsius_to_fahrenheit(100))
Convert a temperature from degrees Celsius to Fahrenheit. 212.0
Generator functions
A function whose body contains the keyword yield is a
generator function.
Calling it does not run the body. Instead, the call returns a
generator: an object that produces the values
lazily, one at a time, only when they are asked
for. You get the values with a for loop or with
next().
Each yield hands one value to the caller and pauses the
function. Its local variables and its position are kept, and the
next request continues right after that yield:
def countdown(start):
print("Starting")
while start > 0:
yield start
start -= 1
print("Liftoff")
for n in countdown(3):
print(n)
Starting 3 2 1 Liftoff
return versus yield
return ends the function and hands back one value; the
next call starts again from the top. yield hands back
one value and pauses: the function can produce many values
over time. A list-building function must compute all values before
it returns; a generator function computes each value only when the
loop needs it, so it uses little memory and can even describe an
endless sequence:
def even_numbers():
n = 0
while True: # endless, but only runs on demand
yield n
n += 2
evens = even_numbers()
print([next(evens) for _ in range(5)])
print(next(evens)) # continues where it paused
[0, 2, 4, 6, 8] 10
Exhausted generators
When the body of a generator function ends, the generator is
exhausted. A for loop then simply
stops; a direct call of next() raises
StopIteration. A generator can be iterated over only
once: to go through the values again, call the generator function
again.
def valid_readings(readings):
for value in readings:
if value is not None:
yield value
temperatures = valid_readings([18.5, None, 21.0])
print(list(temperatures)) # takes all values
print(list(temperatures)) # nothing left
print(next(temperatures))
[18.5, 21.0] [] StopIteration
A generator function is the multi-line form of a generator expression: use the expression for a simple one-line transformation, and a generator function when producing each value needs several statements.