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:

  1. Local — names assigned in the current function.
  2. Enclosing — names in any function that contains the current one (for nested functions).
  3. Global — names at the top level of the module.
  4. Built-in — names Python provides, such as len and print.

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.