Python · Beginner
Functions in Python
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
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 valuesThe 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.
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.
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.
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 · fixdef add_tax(amount): return amount * 1.2 print(add_tax(100))Referring to the function without calling it
Why it goes wrong:
result = areawith no parentheses bindsresultto 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
savingafterapply_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 · fixdef add_item(item, basket=None): if basket is None: basket = [] basket.append(item) return basket
Ways to pass arguments
| Call | How it is matched | Notes |
|---|---|---|
| label("rope", 3) | by position, left to right | positional arguments come before any keyword arguments |
| label("rope", unit="m") | by name | order among keyword arguments does not matter |
| label("rope") | defaults fill the rest | only 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.
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
defdefines a function; the body runs only when the function is called.- Parameters receive the arguments; defaults make parameters optional.
returnsends 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.
def area(width, height):
pass
w = int(input())
h = int(input())
print(area(w, h))
4 ↵ 624def area(width, height):
return width * height
w = int(input())
h = int(input())
print(area(w, h))
Practise this
Related lessons
- Loops in Python: for and whileHow a for loop walks through a sequence and a while loop repeats until a condition fails, with range(), enumerate(), break and continue explained by example.9 min
- Strings in PythonWorking with text in Python: indexing and slicing strings, methods such as strip(), split(), replace() and join(), and formatting output with f-strings.9 min
- Lists in PythonHow Python lists store ordered, changeable collections: creating them, indexing and slicing, adding and removing items, sorting, copying and looping over them.9 min
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.
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.