A Python function is a named block of code you can run whenever you need it. You define it with def, give it inputs (parameters), and send a result back with return. Variables created inside a function are local: they exist only while it runs. If a function never reaches a return, it gives back None.
This guide covers defining and calling functions, arguments and default values, returning results, scope and the mistakes that trip up beginners, with real output throughout.
In this guide
The short version
def name(parameters):defines it.name(arguments)calls it.returnsends a value back. NoreturnmeansNone.- Give a parameter a default (
rate=0.18) to make it optional. - Variables assigned inside a function are local. Read globals freely, but avoid changing them.
Defining and calling a function
The def line names the function and lists its parameters. The indented lines below are its body. Nothing runs until you call the function by name with brackets:
def greet(name):
return "Hello, " + name + "!"
message = greet("Asha")
print(message)
print(greet("Ravi"))
Output
Hello, Asha!
Hello, Ravi!
A function lets you write logic once and reuse it. It also gives that logic a name, which makes code easier to read: greet("Asha") says what it does.
Parameters, arguments and defaults
A parameter is the name in the definition (name). An argument is the actual value you pass when you call it ("Asha"). People mix the two words up constantly, and it rarely matters.
Give a parameter a default value and callers can leave it out. You can also pass arguments by name (keyword arguments), in any order:
def price_with_tax(amount, rate=0.18, currency="INR"):
return f"{amount * (1 + rate):.2f} {currency}"
print(price_with_tax(100))
print(price_with_tax(100, 0.05))
print(price_with_tax(100, currency="USD"))
print(price_with_tax(currency="EUR", amount=200, rate=0))
Output
118.00 INR
105.00 INR
118.00 USD
200.00 EUR
Two habits pay off. Put parameters with defaults after the ones without. And use keyword arguments when a call has several values of the same type, because price_with_tax(100, 0.05) is harder to read than price_with_tax(100, rate=0.05). To accept any number of arguments, see Python *args and **kwargs Explained.
Returning values
The most common function mistake is confusing print with return. print only shows something on screen. return hands a value back so the rest of your program can use it:
def add_print(a, b):
print(a + b)
def add_return(a, b):
return a + b
x = add_print(2, 3)
y = add_return(2, 3)
print(x, y)
Output
5
None 5
The first function printed 5, but gave back nothing, so x is None. The second returned 5, so y holds it. If you want to use the result, return it.
Returning several values
A function can return more than one value. Python packs them into a tuple, and you can unpack them on the other side:
def stats(nums):
return min(nums), max(nums), sum(nums) / len(nums)
low, high, avg = stats([4, 8, 6])
print(low, high, avg)
print(stats([4, 8, 6]))
Output
4 8 6.0
(4, 8, 6.0)
Scope: where variables live
A variable created inside a function is local. It is created when the function runs and disappears when it ends. Assigning to a name inside a function makes a new local variable, even if a global with the same name exists:
total = 100
def show():
total = 5
print("inside:", total)
show()
print("outside:", total)
Output
inside: 5
outside: 100
Outside the function, the local variable simply does not exist:
def make():
secret = 42
make()
print(secret)
Output
NameError: name 'secret' is not defined
When Python meets a name, it looks in this order: Local (inside the function), Enclosing (an outer function), Global (the file) and Built-in (like len). It uses the first match. This is called the LEGB rule.
Changing a global from inside a function
Reading a global is fine. But assigning to it makes Python treat the name as local for the whole function, and that fails when the function reads it first:
count = 0
def add_one():
count = count + 1
try:
add_one()
except UnboundLocalError as e:
print(type(e).__name__)
Output
UnboundLocalError
You can fix it with the global keyword, but that is usually a sign to redesign. Passing the value in and returning the result is cleaner and easier to test:
count = 0
def add_one():
global count
count += 1
add_one()
add_one()
print(count)
def add_one_better(n):
return n + 1
print(add_one_better(count))
Output
2
3
Functions are objects too
In Python a function is a value like any other. You can store it in a variable, put it in a list, pass it to another function, or return it from one. That idea powers map(), sorted(key=...) and decorators:
def square(n):
return n * n
operation = square
print(operation(4))
print(list(map(square, [1, 2, 3])))
print(square.__name__)
Output
16
[1, 4, 9]
square
Read on in Python Decorators Explained Step by Step and Python lambda, map, filter and reduce Explained.
Documenting a function
A string placed on the first line of the body is a docstring. Tools, editors and help() show it, so it is the natural place to say what the function does:
def area(width, height):
"""Return the area of a rectangle."""
return width * height
print(area.__doc__)
print(area(3, 4))
Output
Return the area of a rectangle.
12
Common mistakes
Mistake 1: forgetting to return
The calculation runs, but the result is thrown away:
def double(n):
n * 2
print(double(5))
Output
None
Mistake 2: a mutable default argument
A default value is created once, when the function is defined, not every time it is called. If it is a list or dictionary, every call shares it:
def add_item(item, basket=[]):
basket.append(item)
return basket
print(add_item("pen"))
print(add_item("book"))
def add_item_ok(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
print(add_item_ok("pen"))
print(add_item_ok("book"))
Output
['pen']
['pen', 'book']
['pen']
['book']
The first version remembered "pen" between calls. The safe pattern is to use None as the default and create the list inside the function.
Mistake 3: naming a variable after a built-in
Calling a variable list, sum, max or id hides the built-in of the same name, and the next call to it breaks:
list = [1, 2]
print(list)
try:
list("abc")
except TypeError as e:
print(type(e).__name__)
Output
[1, 2]
TypeError
Mistake 4: changing globals inside functions
It makes code hard to follow and test. Pass values in and return results instead.
Try it yourself
Work out each answer first, then open the solution.
1. Write is_even(n) that returns True or False.
Show solution
def is_even(n):
return n % 2 == 0
print(is_even(4), is_even(7))
Output
True FalseThe comparison n % 2 == 0 is already a boolean, so you can return it directly.
2. Write average(nums) that returns the mean of a list.
Show solution
def average(nums):
return sum(nums) / len(nums)
print(average([2, 4, 9]))
Output
5.03. What does this print?
x = 10
def f():
x = 20
return x
print(f(), x)
Show answer
Output
20 10The x = 20 inside f creates a local variable. The global x is untouched.
4. What does this print?
def f(a, b=2):
return a * b
print(f(3), f(3, 4), f(b=5, a=1))
Show answer
Output
6 12 5f(3) uses the default b=2, f(3, 4) overrides it, and the keyword call f(b=5, a=1) works in any order.
Run these in our free Python compiler.
Frequently asked questions
What is the difference between a parameter and an argument?
A parameter is the variable name in the function definition. An argument is the actual value you pass in when you call the function. In greet("Asha"), "Asha" is the argument.
What is the difference between print and return?
print displays a value on screen and gives back None. return sends a value back to the caller so it can be stored or used in further calculations.
Can a Python function return multiple values?
Yes. return a, b returns a tuple, which you can unpack: x, y = func().
What does a function return if there is no return statement?
None. The function still runs, but the caller gets None back.
What is variable scope in Python?
Scope decides where a name can be used. A variable assigned inside a function is local to it. Python searches Local, then Enclosing, then Global, then Built-in scopes for a name (the LEGB rule).
When should I use the global keyword?
Rarely. It lets a function assign to a module-level variable, but it makes code harder to understand and test. Prefer passing values as arguments and returning results.
Related reading
- Python *args and **kwargs Explained – accept any number of arguments.
- Python lambda, map, filter and reduce Explained – short one-line functions.
- Python Decorators Explained Step by Step – functions that wrap functions.
- Mutable vs Immutable Objects in Python – the idea behind the default-argument trap.
Run this code in your browser
The free Upskly compiler runs Python with nothing to install. Paste the example, change it and see what happens.
Stuck on a traceback?
AI Assist works inside the Python notebook, so you can ask about an error or a concept without leaving the cell.
Test yourself
Timed questions on Functions, Scope and Closures, with an explanation for every answer.