Lesson 08 · Beginner · 19 min

Python Functions

Package a calculation once, give it a name, and reuse it without copying code.

def and callsreturn valuesdefault parameters

Maya has pasted the same total formula into four places, and one copy is already wrong. A function gives that formula one name and one home. What should it return when the order is empty?

A function is a named block of code that can receive inputs and return a result. Functions make programs easier to test, reuse, and read. Define one with def, then call it by name. You will also separate calculation from display and validate at the function boundary.

Define and call

The definition creates the function but does not run it. Calling the function with parentheses runs the body. Parameters are the names in the definition; arguments are the values you pass in.

def greet(name):
    return f"Hello, {name}!"

print(greet("Maya"))

A reusable message

Return a value

return sends a value back to the caller and ends the function. print only displays text; it does not give the caller a usable result. A function with no return statement returns None.

def total(price, quantity):
    return price * quantity

result = total(4.5, 2)
print(result)

Returning a calculation

Defaults and keyword arguments

A default parameter is used when the caller omits that argument. Parameters with defaults must come after parameters without them. Keyword arguments make calls readable when a function has several parameters.

def total(price, quantity=1):
    return price * quantity

print(total(4.5))
print(total(price=4.5, quantity=3))

Defaults and named arguments

Return, don't print

A function that prints is hard to reuse; a function that returns can be combined, tested, and formatted by the caller. Keep calculation and presentation separate. Print at the edge of the program, not in the middle of the calculation.

def line_total(qty, price):
    return round(qty * price, 2)

subtotal = line_total(2, 4.5) + line_total(1, 3.0)
print(f"subtotal: {subtotal:.2f}")

A return value can be composed

Validate at the boundary

Validate inputs where they enter the function, and raise a specific exception with a useful message. The caller can then decide whether to retry, skip the row, or stop. A function that silently returns None hides the failure.

def line_total(qty, price):
    if qty <= 0:
        raise ValueError("qty must be positive")
    if price < 0:
        raise ValueError("price must be non-negative")
    return round(qty * price, 2)

print(line_total(2, 4.5))
try:
    line_total(0, 4.5)
except ValueError as error:
    print(type(error).__name__, error)

Validate once, fail clearly

Never use a mutable default

Default arguments are evaluated once, when the function is defined. A list default is therefore shared by every call that does not pass its own list. Use None as the default and create a new list inside the function. This is not a style preference; it prevents data from leaking between calls.

def add_item(item, basket=None):
    if basket is None:
        basket = []
    basket.append(item)
    return basket

print(add_item("latte"))
print(add_item("tea"))

A fresh list for each call

Key points

  • def defines a function; parentheses call it.
  • return gives a value back; print only displays it.
  • Default parameters make optional arguments convenient.
  • Keep each function focused on one job.
  • Return values are composable; print is a side effect.
  • Use None as the default when the real default is a mutable object.

Common mistakes

  • Forgetting to call the function, so the definition never runs.
  • Using print inside a function when the caller needs a value returned.
  • Putting a parameter without a default after one with a default.
  • Printing inside a function when the caller needs the value.
  • Defining def add(item, basket=[]) and sharing one list across calls.
Your turn

Write a function that takes a price and quantity and returns the total, then print the result.

Try it yourself

Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.

In-browser PythonRuns locally · no account
First run downloads Pyodide from a CDN. Use Run code after editing.

Practice this lesson

12 questions with immediate explanations.

See all 12 answersStart practice
← DictionariesError handling →