Topic 5.1
Defining and Calling Functions
In one line
A function is a named block of code that you define once with def and run whenever you call it by name. It can receive values (parameters), and hand a value back to the caller with return; if it never reaches a return, it gives back None.
Think of it like this
A recipe card for "masala tea" stuck on the fridge. You don't rewrite the steps every morning; you say "make masala tea" and follow the card. If the card says "for N cups", you can make two cups today and five tomorrow with the same card. A function is a recipe card for code: the steps are written once, given a name, and followed whenever someone asks for it.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Function
- A named block of code that you can run again and again by calling its name.
- def
- The keyword that starts a function definition. It stands for "define".
- Call
- To run a function by writing its name followed by round brackets, such as
greet("Asha"). - Parameter
- A name in the
defline that receives a value when the function runs. - Argument
- The actual value you give a function in a call.
- Body
- The indented lines under the
defline. They run each time the function is called. - return
- Ends the function and hands a value back to the caller.
- Return value
- The value a call turns into. Without a
return, it isNone. - Docstring
- A string on the first line of a function body that describes what the function does.
Step by step
01Define once, call many times
The def line gives the function a name and lists its parameters. The indented body is the recipe. Nothing in the body runs while Python is reading the def; Python only remembers it.
A call such as greet("Asha") jumps into the body with name set to "Asha", runs the lines, then comes back to where the call was.
def greet(name):
return "Hello, " + name + "!"
print(greet("Asha"))
print(greet("Ravi"))02Parameters and arguments
name is the parameter: it exists only while the function runs, and it is a fresh variable on every call. Calling greet("Ravi") does not change the earlier call; each call gets its own name.
The order of arguments matters when there is more than one parameter: Python matches them left to right. Topic 5.2 shows the other ways to match them.
def rectangle_area(width, height):
return width * height
print(rectangle_area(3, 4)) # width = 3, height = 4
print(rectangle_area(4, 3)) # same answer, but the roles swapped03return hands the answer back
After return, the function stops. Any line below it in the same path never runs. The call becomes the returned value, so you can store it, print it, or use it inside a bigger expression.
To send back several values, list them with commas. Python packs them into a tuple, and you can unpack the tuple into separate names at the call.
def rectangle(width, height):
area = width * height
perimeter = 2 * (width + height)
return area, perimeter # one tuple with two values
a, p = rectangle(3, 4) # unpacking
print(a, p) # 12 1404No return means None
If the body finishes without hitting a return, Python quietly returns None. The same is true for a function that only prints. Many bugs come from using the result of such a function: total = show(5) + 1 fails because None + 1 is not allowed.
A function can also have several return lines on different paths, such as inside an if or a loop. The first one reached ends the call. If no path reaches a return, the answer is None.
def first_even(numbers):
for n in numbers:
if n % 2 == 0:
return n # leaves the function at once
# if the loop ends, we fall off the end -> None
print(first_even([5, 7, 8, 10])) # 8
print(first_even([5, 7, 9])) # None05Docstrings: a note for the next reader
A string literal as the first statement of the body becomes the function's docstring. It does not run as code; Python stores it on the function as __doc__. It is the standard place to say what the function does, and help(greet) prints it.
Write the docstring as a short command: "Return a greeting for the given name." Not "This function returns...".
def greet(name):
"""Return a greeting for the given name."""
return "Hello, " + name + "!"
print(greet.__doc__)06What Python does at def and at call
When Python reaches def greet(name): ... it builds a function object (the code of the body plus the parameter list, stored in memory like any other value) and binds the name greet to it, exactly as x = 5 binds x to a number. That is why you can later rebind the name, or assign the function to another name. Topic 5.6 builds on this idea.
At a call, Python creates a new frame: a small private area holding the parameters and any variables created in the body. When the function returns, the frame is thrown away, and the values in it vanish unless they were returned. This is why variables made inside a function are not visible outside (Topic 5.5).
07Calling with the wrong number of arguments
Python checks the call against the parameter list before running the body. Too few or too many arguments is a TypeError that names the function and the missing parameter. The check happens at the call, not inside the function, so the error points at the line that made the call.
Try it yourself
- 1
Predict, then run
In the first example, say out loud what
show_greeting("Ravi")returns before you press Run. Then check the line that printsresult. - 2
Add a second parameter
Change
greettodef greet(name, greeting):and returngreeting + ", " + name + "!". Update both calls so they pass two values, for examplegreet("Asha", "Namaste"). Then remove the second value from one call. What happens? Read the error message carefully. - 3
Return early
In
first_even, addprint("checking", n)as the first line inside the loop. Run it with[5, 7, 8, 10]. Notice that10is never checked:returnleft the function at8.
Code & diagrams
greet gives back a value. show_greeting only prints, so what it returns is None.
Expected output
greet returned: Hello, Asha!
Hello, Ravi!
show_greeting returned: None
Docstring: Return a greeting for the given name.rectangle returns a tuple that is unpacked into two names. first_even returns None when no even number exists.
Expected output
area: 12 perimeter: 14
both together: (12, 14)
8
None
NoneBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Forget an argument
Call greet() with nothing between the brackets.
def greet(name):
return "Hello, " + name + "!"
print(greet())Break #2
Use the result of a function that only prints
Add 10 to the value returned by a function that has no return.
def add(a, b):
print(a + b)
total = add(2, 3) + 10
print(total)Myth vs fact
Myth
Defining a function runs it.
Fact
def only stores the function. The body runs when you call it. A function that is never called never runs.
Myth
A function that prints a value has returned that value.
Fact
print sends text to the screen. The function's return value is None unless it uses return.
Myth
Parameters and arguments are two names for the same thing.
Fact
Parameters are the names in the def line. Arguments are the values passed in a call. Each call binds its arguments to the parameters.
Myth
A function can return only one value.
Fact
It returns exactly one object, but that object can be a tuple (or list, or dict) holding many values, which you can unpack at the call.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
A function is an ordinary object (type
function).defcreates it at run time and binds a name to it, so the same name can be bound again later, and functions can be stored in lists and dictionaries (Topic 5.6). In CPython each call gets its own frame (since 3.11 it lives on a cheap per-thread stack, and a full frame object is built only if something such as a traceback or debugger asks for it). Very deep call chains are limited by the recursion limit (Topic 5.8). The samedefrun twice makes two separate function objects that share one code object, which is why a closure factory (Topic 5.7) can hand out many functions cheaply. - ▸
Calling a Python function is not free: each call costs roughly the time of a few simple operations. In a hot loop of millions of iterations, moving a tiny function inline can matter. For almost everything else, clarity beats micro-speed. Measure before you inline.
- ▸
Prefer functions that return their result over functions that print it. A returning function can be tested with
assert add(2, 3) == 5, reused in a web response, logged, or piped into another function. A printing function can only be read by a human. - ▸
In AI work, a plain function with a clear name, typed parameters and a docstring is also the unit a model can be allowed to call ("tool use"). The name and docstring become the instructions the model sees. Topic 16.10 builds this.
Remember this
- 1
You create a function with the word
def(short for *define*), a name, round brackets and a colon. The indented lines below are its body. Defining a function does not run it. It only stores the recipe under that name. The body runs each time you call the function by writing its name followed by round brackets, such asgreet("Asha"). - 2
The names inside the brackets of the
defline are parameters: empty slots that the function fills in each time it runs. The actual values you supply in a call are arguments. Indef greet(name):the wordnameis a parameter; ingreet("Asha")the text"Asha"is an argument. People mix these words up in conversation, but it helps to keep them apart: parameters are in the recipe, arguments are the ingredients you bring today. - 3
returnends the function immediately and hands a value back to whoever called it. The call itself then becomes that value, sogreet("Asha") + "!!"works like"Hello, Asha!" + "!!". Areturncan send back any value, including a tuple of several values, which Python's unpacking (Topic 4.3) then splits into separate names. - 4
A function that reaches the end of its body without meeting a
returnstill gives something back: the special valueNone(Topic 1.4). The same happens for a barereturn. This surprises beginners most often withprint: a function that only prints shows text on the screen but returnsNone, so you cannot use its "answer" in further calculations. Printing is for people; returning is for the rest of the program. - 5
The first string in a function's body, if it is a plain string on its own line, is its docstring: a note that says what the function does. Python stores it in
function.__doc__, and tools such ashelp()and editors show it. Write a one-line docstring for every function you share with others (Topic 5.9 covers styles in depth). - 6
Why bother? Functions remove copy-paste (fix a bug once, not in ten places), give a group of steps a clear name that explains what it is for, let you test small pieces separately, and keep each part small enough to hold in your head. In AI work, a function with a clear name, typed parameters and a docstring is exactly what an LLM (a large language model, the kind of AI behind chat assistants) is shown when it is allowed to "call a tool", which means asking your program to run that function. You will build this in Topic 16.10.
Explain it without notes
What is the difference between a parameter and an argument?
What does a function return if it has no return statement? Why does that matter?
What happens when Python reaches a def statement, and what happens when the function is called?
Why prefer return over print inside a function that computes something?
Is Python pass-by-value or pass-by-reference?
Practice
Write a function square(n) that returns n * n. Print square(7).
Write a function min_max(numbers) that returns the smallest and largest items of a list as two values. Unpack the result into low and high and print both.
Write a function describe(name, age) that returns the text Asha is 12 years old. for describe("Asha", 12). Print the result of calling it with your own values.
Trade-offs
- ↔
Many small functions versus one long script. Small functions are easy to name, test and reuse, but too many tiny ones scatter the logic and make the reader jump around. Split where a piece has a clear name and a clear job.
- ↔
Returning a tuple versus several functions. Returning
(area, perimeter)is convenient, but callers must remember the order. For more than three or four values, a dictionary or a small class (Phase 8) is clearer.
Done when you can
Done when you can write a function with
def, parameters and areturn, and call it.Done when you can explain parameters versus arguments with an example.
Done when you can say what a function without
returngives back, and why that causes bugs.Done when you can return two values and unpack them at the call.
Done when you can read a
missing 1 required positional argumenterror and fix the call.