Python · Beginner

Functions in Python

9 min readUpdated September 24, 2026Every example verified

In short: A function is a named, reusable block of code defined with def. Calling it runs the block with the arguments you pass, and return hands a result back to the caller. Variables created inside a function are local to that call, and a function without a return statement returns None.

Why functions exist

A function packages a piece of logic under a name so it can be run from anywhere, as often as needed, with different inputs each time. Without functions, a calculation needed in three places must be written three times, and a fix must be made three times. With a function, the logic lives once, has a name that says what it does, and can be tested on its own.

def name(parameters): starts a definition; the indented block is the body. Defining a function does not run it. Nothing happens until a call, name(arguments), which binds each parameter to the corresponding argument and then executes the body. The names used in the definition are called parameters; the values supplied in the call are arguments.

return value ends the call and sends the value back to the caller, where it can be stored, printed or used in a larger expression. A function may return from several places, and it may return several values at once by separating them with commas, which really returns one tuple that the caller can unpack. If execution reaches the end of the body without a return, or hits a bare return, the call evaluates to None. This is the single most important distinction for beginners: print() shows a value on the screen and gives back nothing useful, while return gives the value to the code that asked for it. A function that prints its answer cannot have that answer used in a calculation.

Parameters can carry defaults: def label(item, quantity=1) lets callers omit quantity. Arguments can be passed by position or by name (label(quantity=2, item="rope")), and naming them makes calls with several values readable. Parameters with defaults must come after those without.

Every call gets its own local namespace. Variables assigned inside the body exist only during that call and are invisible outside, so two functions can both use a variable called total without interfering. A function can read variables defined at the top level of the file, but assigning to one inside the body creates a new local instead. Passing values in as parameters and getting results out with return is the clean way to communicate, and it keeps each function understandable on its own.

Syntax

 Python · syntax
def function_name(parameter1, parameter2=default):
    """Optional docstring describing the function."""
    body
    return result          # optional; omit to return None

value = function_name(argument1)                  # positional
value = function_name(argument1, parameter2=5)    # keyword argument
a, b = function_name(x)     # unpack a function that returns two values

The def line ends with a colon and the body is indented, exactly like an if or a loop. The function must be defined above the first line that calls it.

Define, call, return

One discount function, called four times with different arguments.

 Python
def apply_discount(amount, percent):
    saving = amount * percent / 100
    return amount - saving

print(apply_discount(200, 10))
print(apply_discount(80, 25))
bill = apply_discount(50, 0)
print("Final bill:", bill)
print(apply_discount(120, 50) + apply_discount(30, 0))

Output

180.0
60.0
Final bill: 50.0
90.0

The body runs once per call with amount and percent bound to that call's arguments. Because the function returns its result rather than printing it, the caller decides what to do with it: print it, store it in bill, or add two results together on the last line. The results are floats because / always produces a float.

Default values and keyword arguments

Two of the three parameters have defaults, so callers can leave them out or name them.

 Python
def label(item, quantity=1, unit="pcs"):
    return f"{quantity} {unit} of {item}"

print(label("nails"))
print(label("rope", 3, "m"))
print(label("paint", unit="L", quantity=2))
print(label(quantity=6, item="bolts"))

Output

1 pcs of nails
3 m of rope
2 L of paint
6 pcs of bolts

The first call supplies only the required parameter and the defaults fill in the rest. The second passes all three by position. The third and fourth pass arguments by name, so their order no longer matters and the call documents itself. Mixing is allowed as long as the positional arguments come first.

Returning nothing, returning two things, and local names

One function only prints; the other returns a pair.

 Python
def announce(word):
    print("Checking", word)

def split_minutes(total):
    hours = total // 60
    return hours, total % 60

result = announce("kayak")
print(result)
hours, minutes = split_minutes(135)
print(hours, "h", minutes, "min")
print(split_minutes(59))

Output

Checking kayak
None
2 h 15 min
(0, 59)

announce prints but has no return, so result is None; if the message were needed elsewhere it would have to be returned. split_minutes returns two values as a tuple, unpacked into hours and minutes at the call site and printed whole on the last line. The hours inside the function and the hours outside are different variables: the local one disappears when the call ends, and the outer one is created by the unpacking assignment.

Common mistakes

  • Printing inside the function instead of returning

    Why it goes wrong: A function that prints its answer gives the caller None, so total = add_tax(100) stores nothing useful and the value cannot be reused or tested.

    Fix: Return the value, and let the caller print it.

     Python · fix
    def add_tax(amount):
        return amount * 1.2
    
    print(add_tax(100))
  • Referring to the function without calling it

    Why it goes wrong: result = area with no parentheses binds result to the function object itself, and printing it shows something like <function area at 0x...>.

    Fix: Call it with parentheses and the arguments: result = area(3, 4).

  • Expecting a local variable to exist after the call

    Why it goes wrong: Names assigned inside the body live only during the call. Reading saving after apply_discount(200, 10) raises NameError.

    Fix: Return the value you need, or compute it from the returned result.

  • Using a mutable default such as an empty list

    Why it goes wrong: def add_item(item, basket=[]) creates one list when the function is defined, not one per call, so items pile up across calls that rely on the default.

    Fix: Default to None and create the list inside the body.

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

Ways to pass arguments

CallHow it is matchedNotes
label("rope", 3)by position, left to rightpositional arguments come before any keyword arguments
label("rope", unit="m")by nameorder among keyword arguments does not matter
label("rope")defaults fill the restonly parameters with defaults may be omitted

Where you use this

Input handling is a natural first function. Every exercise reads lines and converts them; wrapping that in read_int() means the conversion, and any validation you add later, lives in one place. The same goes for the logic under test: write solve(values) so that it returns the answer, and keep the input and output code outside it. You can then call solve([3, 1, 2]) by hand to check it, which is far quicker than retyping input each time. Larger programs are built the same way, as small functions that each do one thing and pass results to one another.

 Python · in practice
def read_int():
    return int(input().strip())

def solve(values):
    return max(values) - min(values)

n = read_int()
values = []
for _ in range(n):
    values.append(read_int())
print(solve(values))

Key points

  • def defines a function; the body runs only when the function is called.
  • Parameters receive the arguments; defaults make parameters optional.
  • return sends a value to the caller; without it the call gives None.
  • Return values so they can be reused; print only at the edges of the program.
  • Variables assigned inside a function are local to that call.
  • Several values can be returned as a tuple and unpacked by the caller.

Try it yourself

Complete the function area so that it returns the width times the height. The rest of the program reads two integers and prints the result of calling it.

Your program
def area(width, height):
    pass

w = int(input())
h = int(input())
print(area(w, h))
Input the program receives: 4 ↵ 6
Expected output: 24

Practise this

Open the Python playground

Frequently asked questions

What is the difference between return and print in a function?

print writes text to the screen and is a side effect; the function still evaluates to None. return ends the function and gives a value back to the code that called it, so the caller can store it, compare it or pass it on. Use return for results and print only where the program actually needs to show something.

Can a Python function return more than one value?

Yes. return a, b builds a tuple (a, b) and returns it; the caller writes x, y = f() to unpack the two parts. This is how functions report a result together with a status, or split a value into components such as hours and minutes.

What happens if I call a function before it is defined?

Python raises NameError, because the def statement has not run yet and the name does not exist. A definition must be executed before the call. Inside another function's body the order is looser: the call is only evaluated when that function runs, by which time the definition usually exists.

Progress is stored only in this browser.

How this page was checked. Every program on it was run with CPython 3.11 at build time; runs in your browser on CPython 3.14 (Pyodide) by the publishing checks, and the output shown is what it printed. The Run buttons execute the same code on your device; nothing you type is sent anywhere.