Defining and calling functions
You have been calling functions since your first line of code — print, len,
input, range. This module is about writing your own, and it is the biggest
single step in the course. Functions are how programs stop being one long script
and start having a shape.
Defining one
def greet():
print("Hello!")
def starts a definition. greet is the name. The empty brackets say it takes
no input. The colon and indentation work exactly as they do for if and for.
Running that file prints nothing. Defining a function does not run it. You have described some behaviour and given it a name; nothing happens until you ask for it:
greet()
Hello!
The brackets are the call. This is the same distinction as module 1: print is
the function, print() runs it.
def greet():
print("Hello!")
greet()
greet()
greet()
Three lines of output from one definition — which is the first reason functions exist.
Taking input
Values in the brackets are parameters:
def greet(name):
print(f"Hello, {name}!")
greet("Priya")
greet("Arjun")
Hello, Priya!
Hello, Arjun!
name exists only inside the function, taking whatever value was passed in.
Two or more, separated by commas:
def greet(name, city):
print(f"Hello, {name} from {city}!")
greet("Priya", "Pune")
Order matters. greet("Pune", "Priya") runs perfectly and prints nonsense —
the sort of bug that only shows up when somebody reads the output.
Pass the wrong number and Python stops immediately:
greet("Priya")
TypeError: greet() missing 1 required positional argument: 'city'
An unusually helpful error: it names the function and the missing parameter.
Parameter or argument? The name in the definition is a parameter; the value you pass is an argument. People use the words interchangeably and the error messages say "argument", but the distinction is occasionally useful.
Giving something back
Printing is not the same as returning:
def add(a, b):
print(a + b)
result = add(2, 3)
print(result)
5
None
It printed 5, then result was None. The function displayed an answer
without giving one back, so nothing was available to use.
return fixes it:
def add(a, b):
return a + b
result = add(2, 3)
print(result)
print(add(10, add(3, 4)))
5
17
Now the result is a value like any other — assignable, printable, passable straight into another call.
Return, do not print, unless printing is the function's job. A function that prints can only ever put text on a screen. A function that returns can be used anywhere: written to a file, summed, tested. Returning is almost always the more useful choice, and it is what makes a function testable in module 10.
return also ends the function immediately:
def check_age(age):
if age < 0:
return "Invalid"
if age < 18:
return "Minor"
return "Adult"
The first return that runs ends it. No elif needed, because reaching line
three means line two did not return.
This is the guard clause pattern from the if lesson, now with a proper
tool. Handle the awkward cases, return early, and the main path stays flat.
Why bother
Four reasons, in rough order of importance.
You stop repeating yourself. Logic written once, used everywhere. When it changes, it changes in one place — and if it is wrong, it is wrong in one place rather than the four you remember and the fifth you do not.
You can name a chunk of work. This:
total = subtotal + (subtotal * 0.18)
versus:
total = apply_gst(subtotal)
The second says what is happening. Naming things is most of what makes code readable, and a function is how you name behaviour.
You can think about one thing at a time. Once apply_gst works, you stop
thinking about tax. Programs get large; this is how you keep them in your head.
You get return, which escapes everything. Remember break only leaving
the inner loop:
def find_in_grid(grid, target):
for row in grid:
for cell in row:
if cell == target:
return True
return False
No flag, no double break. return leaves the function outright, however many
loops deep you are. This is the tidy answer promised in module 3.
Order matters
Python reads top to bottom, so a function must be defined before it is called:
greet("Priya")
def greet(name):
print(f"Hello, {name}!")
NameError: name 'greet' is not defined
Same NameError as a misspelled variable, for the same reason: at that moment,
Python has not been told what greet means.
The convention is definitions at the top, the code that runs them at the bottom.
Calling from inside another
Functions call functions. That is the whole idea:
def apply_gst(amount):
return amount + (amount * 0.18)
def format_rupees(amount):
return f"₹{amount:,.2f}"
def print_total(subtotal):
total = apply_gst(subtotal)
print(format_rupees(total))
print_total(1250)
₹1,475.00
Each function does one small thing. print_total reads almost as a sentence,
and any one of them can be fixed without touching the others.
What makes a good function
One job. If the name needs "and" in it, it is probably two functions.
A name that says what it does. Verbs for actions — calculate_total,
send_email, is_valid. A function called process or handle_data tells a
reader nothing.
Short. There is no rule, but if it does not fit on a screen it is usually doing too much.
Predictable. Given the same input, give the same output, and avoid reaching out to change things elsewhere. Functions like that are easy to reason about and trivial to test.
Practice
- Write
greet()that prints a fixed greeting. Call it three times. - Change it to take a name, then a name and a city.
- Write
add(a, b)that prints the sum, and try to use the result. Then rewrite it withreturnand see the difference. - Write
celsius_to_fahrenheit(c)returning the converted value. Print several conversions using one function. - Write
is_even(n)returningTrueorFalse. Use it inside anif. - Write
classify_age(age)using guard clauses, returning"Invalid","Minor","Adult"or"Senior". Noelif. - Write
find_in_grid(grid, target)as above. Then try writing the same thing without a function, using flags and twobreaks. Compare them. - Call a function before defining it. Read the
NameErrorand fix it.
Next: the different ways to pass arguments, and a default value that will eventually catch you out.
Stuck on this lesson?
Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.
About the internship