Python + AI/ML · Tutorial 2 of 5
Python Functions: writing code you can reuse
By the FUTEAC Team · 28 October 2026 · 10 min read · Beginner
In short
A function is a block of code that takes inputs, called parameters, does one job, and hands back a result with return. Define it once with def and call it as many times as you like, with different inputs. Functions turn repeated code into one reusable piece — so a fix in one place fixes every use of it.
defnames the function; the body runs only when you call it. Defining a function does nothing by itself.- Parameters are the inputs a function accepts; arguments are the values you pass when you call it. One function, many different calls.
returnhands a value back to the caller. Without it, a function returnsNone— Python's way of saying "nothing".- A variable created inside a function is local. It does not exist outside the function.
- This tutorial feeds the Python Programming Foundations course (/course/python-programming-foundations) and the Python Programming skill (/skill/python).
Before you start
What is a function, and why write one?
A function is a shortcut you define once and use many times. Suppose you want to greet three people. Without a function you write the same line three times:
print("Hello, Ayesha!")
print("Hello, Bilal!")
print("Hello, Sara!")That works — until the greeting has to change, or there are thirty people instead of three. A function does the job once, with a placeholder for the name:
def greet(name):
print(f"Hello, {name}!")
greet("Ayesha")
greet("Bilal")
greet("Sara")Expected output:
Hello, Ayesha!
Hello, Bilal!
Hello, Sara!Same three lines of output, but now the greeting lives in one place. Change "Hello" to "Salam" inside the function and all three greetings change. That is the whole point of a function: write the logic once, reuse it everywhere, fix it in one place.
You have already been using functions all along — print(), len() and sum() are built-in functions. Now you are writing your own.
How do I define and call a function?
A function definition has four parts:

def double(number):
return number * 2deftells Python a function definition is starting.doubleis the function's name — pick a verb that says what it does.(number)holds the parameters — the inputs the function needs.- The colon and the indented lines are the body — the work the function does.
Defining the function does not run it. Nothing happens until you call it, by writing its name with parentheses:
print(double(21))Expected output:
42Two details beginners trip over: the body must be indented (four spaces, like a loop body), and Python reads your file top to bottom — so a call written *above* the def fails with NameError, because the function does not exist yet at that point. Define first, call after.
What do parameters and arguments mean?
Parameters are the placeholders in the definition; arguments are the real values you pass in a call. In def add(a, b), a and b are parameters. In add(3, 4), 3 and 4 are the arguments.
def add(a, b):
return a + b
print(add(3, 4))
print(add(10, 20))
print(add(-5, 5))Expected output:
7
30
0One function, three different answers — the parameters are what make it reusable. A function can take as many parameters as it needs, and it can take none at all:
def say_ready():
return "Ready!"
print(say_ready())Expected output:
Ready!The empty parentheses are still required: say_ready without them is the function itself, not a call to it.
How does `return` work — and what happens without it?
return is how a function hands a value back to whoever called it. The caller can print it, store it, or feed it into another calculation:
def average(numbers):
return sum(numbers) / len(numbers)
result = average([10, 20, 30])
print(result)
print(result * 2)Expected output:
20.0
40.0Because average *returns* the value, result holds 20.0 and can be reused. Compare that with a function that only prints:
def show_average(numbers):
print(sum(numbers) / len(numbers))
show_average([10, 20, 30])That prints 20.0 too — but nothing comes back, so there is nothing to store or reuse. Printing shows a value to a human; returning gives a value to your program. For anything you want to reuse — a total, an average, a decision — return it.
A function without a return statement still returns something: None, Python's value for "nothing here":
def no_return():
x = 5
print(no_return())Expected output:
NoneNone is not an error — it is the honest answer to "what did this function give back?" If you ever see None where you expected a number, check whether you forgot return.
A return also ends the function immediately: any line after it in the same block never runs.
What is scope — why can't a function see my variables?
A variable created inside a function belongs to that function. It is local: it exists while the function runs, and it is gone afterwards.
def make_total(amounts):
total = 0
for amount in amounts:
total = total + amount
return total
print(make_total([100, 200]))
print(total)Expected output:
300
NameError: name 'total' is not definedThe first line prints 300 — inside the function, total works fine. The second line fails because outside the function there is no variable called total at all. The function returns the *value*; the variable itself stays inside.
This is a feature, not a limitation. Because each function's variables are private, two functions can both use a variable called total without interfering with each other — and a bug inside one function cannot silently change a variable somewhere else in your program. If a value needs to leave a function, return it; if a value needs to enter one, pass it as a parameter.
How do default values and keyword arguments work?
Sometimes a parameter has an obvious usual value. Give it a default, and callers can leave it out:
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Ayesha"))
print(greet("Bilal", "Salam"))
print(greet(name="Sara", greeting="Hi"))Expected output:
Hello, Ayesha!
Salam, Bilal!
Hi, Sara!Three things to notice:
greet("Ayesha")uses the default, so the greeting is"Hello".greet("Bilal", "Salam")passes both arguments by position — first value to the first parameter, second to the second.greet(name="Sara", greeting="Hi")passes them by keyword — the name of the parameter, so the order does not matter.
One rule: parameters with defaults must come after parameters without them — def greet(greeting="Hello", name) is a syntax error, because Python would not know which value goes where.
Worked example: expense-tracker helpers you can reuse
In the Python Loops tutorial you totalled a list of expenses with a loop written out in full. Turn that into functions, and the same logic becomes reusable — this is the first step towards the course project, Build a Personal Expense Tracker in Python. Save this as expense_helpers.py and run it with python expense_helpers.py.
expenses = [1200, 850, 2300, 450]
def total_spent(amounts):
total = 0
for amount in amounts:
total = total + amount
return total
def average_spent(amounts):
return total_spent(amounts) / len(amounts)
def summary(amounts):
return f"Spent {total_spent(amounts)} in {len(amounts)} expenses; average {average_spent(amounts)}."
print(total_spent(expenses))
print(average_spent(expenses))
print(summary(expenses))Walk through it before running: total_spent adds 1200 + 850 + 2300 + 450 = 4800. average_spent reuses total_spent instead of repeating the loop, and divides by 4 expenses: 4800 ÷ 4 = 1200.0. summary calls both helpers and builds one sentence.
Expected output:
4800
1200.0
Spent 4800 in 4 expenses; average 1200.0.Notice what the functions buy you: average_spent calls total_spent — functions calling functions is normal, and it is how real programs stay short. And if the expenses list changes, every answer updates with no edits to the logic: try expenses = [500, 500, 500] and the same three lines print 1500, 500.0, and the matching summary.
Try it yourself
Extend the worked example. Add a function called biggest_expense that takes a list of amounts and returns the largest one (hint: Python's built-in max() does the work — your function just wraps it). Then add a function called over_budget that takes a list of amounts and a budget, and returns True if the total is over the budget and False otherwise. Call both on the expenses list from the worked example with a budget of 5000, and check your answers before looking: the biggest expense is 2300, and 4800 is not over 5000, so over_budget should return False. When both work, test yourself in the Module Quiz: Functions and Files on the Python Programming Foundations course page (/course/python-programming-foundations).
Continue in the free course: Python Programming Foundations →
Common mistakes
- Forgetting
return. The function computes the right answer and throws it away — the caller getsNone. If a function call gives youNonewhere you expected a number, check for a missingreturnfirst. - Forgetting the parentheses when calling.
doubleis the function;double(21)is the result42. Printingdoublewithout parentheses prints something like<function double at 0x...>— the function object itself, not its answer. - Using a local variable outside the function. A variable created inside a function does not exist outside it —
print(total)aftermake_totalis aNameError. Return the value if you need it. - Printing instead of returning. A function that prints its answer cannot feed that answer into the next step. If you need the value later — to compare it, store it, or total it —
returnit. - Passing the wrong number of arguments.
add(3)fails withTypeError: add() missing 1 required positional argument: 'b'— the call must supply one argument for every parameter that has no default. Read the error: it names the missing parameter.
Frequently asked questions
When should I write a function?
Whenever you catch yourself writing the same logic twice, or when one block of code does one clear job — totalling a list, checking a budget, formatting a message. A good rule: if you can name what the block does in a short verb phrase ("total the expenses"), it is a function.
What is the difference between print and return?
print shows a value on screen for a human. return hands a value back to the calling code so the program can use it. A function can do both, but only return makes the value reusable.
Can a function return more than one value?
Yes — return them separated by commas and Python packs them into a tuple: return total, average gives back both, and the caller unpacks them with total, average = summary(numbers). The next tutorial in this series, Python Lists and Dictionaries, explains tuples properly.
What is None, and should I worry about it?
None is Python's value for "no value" — it is what every function returns when it reaches the end without a return. It is not an error by itself, but it is a clue: if you see None where you expected a number, you almost certainly forgot to return it.
Do I need a main function like in other languages?
No. A Python script runs top to bottom, and small scripts need no main at all. Larger programs sometimes define one for tidiness — the Python Programming Foundations course introduces it when the expense-tracker project grows. ---
Follow the Python + AI/ML Beginner Roadmap
Learn Python from zero and take your first steps into AI and machine learning. Free, step by step, at your pace.
View the Roadmap