Learn
04.1 | DEFINING FUNCTIONS AND RETURNING VALUES
01 | GIVE A JOB A NAME
Imagine a coding club prints a welcome message in three different places. Copying the same instructions works initially, but changing the message means finding and editing every copy. A function lets you define that job once and request it whenever it is needed.
A function is a callable object containing a named set of instructions. You already call built-in functions such as print(), len() and input(). Now you will create your own functions with def. A useful name describes the job, for example show_welcome or calculate_area.
A function is not automatically useful just because it makes a program shorter. Its boundary should make an operation easier to understand, test or reuse. Start with a small job that has a clear purpose.
02 | DEFINE FIRST, CALL WHEN NEEDED
The keyword def starts the definition. After it come the function name, parentheses and a colon. The indented instructions form the body, meaning the group of statements belonging to the function. Indentation shows where that group begins and ends.
Executing the def statement creates the function and binds its name. It does not execute its body at that moment. The later call show_welcome() runs the body. Without the parentheses, show_welcome refers to the function object rather than requesting this execution.
The call must happen after Python has executed the definition. In a simple file, place the definition above the first top-level call. A body can call another function defined later in the file provided that other definition has executed by the time the body runs.
def show_welcome():
print("Welcome to the coding club")
print("Try, test and explain")
print("Before the call")
show_welcome()
print("After the call")EXPECTED OUTPUT
Before the call Welcome to the coding club Try, test and explain After the call
03 | FOLLOW THE CALL AND RETURN
Normally Python follows statements in source order. At a function call, execution enters the function body. When that function finishes, execution continues in its caller, which is the code that made the request.
The caller does not have to know every internal step. It should know the function’s contract: what it receives, what it does and what it returns. A contract is a clear description of behaviour, not an extra Python keyword.
Calling twice runs the body twice. Defining once does not cache a previous answer or prevent later work. If the body reads input or prints a message, those actions happen again on each call.
def get_starting_score():
return 10
first = get_starting_score()
second = get_starting_score()
print(first, second)EXPECTED OUTPUT
10 10
04 | RETURN GIVES A RESULT TO THE CALLER
return sends a value back from the current function call. In result = get_starting_score(), the call evaluates to 10, and assignment stores that value under result. The caller can print it, compare it or use it in a calculation.
A returned value does not automatically appear on the screen. Displaying output is a separate decision made by print(). This separation matters when the same calculation is later used in a website, game or report.
return also ends the current call immediately. Statements after that executed return in the same body are not reached. It leaves the function, not just an inner loop and not the whole application.
def get_starting_score():
return 10
print("This is not reached")
score = get_starting_score()
print("With bonus:", score + 5)EXPECTED OUTPUT
With bonus: 15
05 | PRINT AND RETURN HAVE DIFFERENT JOBS
A common beginner mistake is to print the correct number inside a function and expect its caller to receive that number. print() displays text; it does not make the enclosing function return the displayed value.
A function that reaches the end without an explicit return value returns None. None is a special value used to represent absence, not the integer zero, empty text or False. A bare return also returns None.
Some functions are intended to perform an action, such as showing instructions, and return None. That is acceptable. The mistake is using their result as if they were calculation functions.
def display_score():
print(10)
def provide_score():
return 10
shown = display_score()
provided = provide_score()
print("Displayed function result:", shown)
print("Provided function result:", provided)EXPECTED OUTPUT
10 Displayed function result: None Provided function result: 10
06 | SEND INFORMATION INTO A FUNCTION
A function often needs different data for different calls. A parameter is a name in the definition that receives supplied information. An argument is the value or expression supplied by a caller. In square(4), 4 is the argument; number is the parameter in def square(number).
Python binds number to the supplied value for that call. return number * number calculates a result using it. The caller can store the returned value under any suitable name; the parameter and caller variable do not need matching names.
A normal required parameter needs an argument. Calling square() without one produces TypeError. The next lesson explores multiple parameters, defaults and scope.
def square(number):
return number * number
side = 4
area = square(side)
print("Area:", area)
print("Another square:", square(7))EXPECTED OUTPUT
Area: 16 Another square: 49
07 | EVERY RELEVANT ROUTE NEEDS ITS RESULT
Suppose a function reports whether a score is a pass. If one route returns True and the other simply ends, the second route produces None. It does not automatically produce False. Decide what every intended route should return.
A Boolean calculation can return the comparison itself. This is often clearer than an unnecessary chain returning True and False separately. State assumptions: a numeric pass rule does not validate arbitrary text or establish a permitted score range.
A function definition can also begin with a docstring, a string explaining the job. It belongs inside the body as the first statement and can be read with help(). Use it to record useful assumptions rather than repeating the name.
def is_pass(score):
"""Return whether a numeric score is at least 50."""
return score >= 50
print(is_pass(49))
print(is_pass(50))EXPECTED OUTPUT
False True
08 | RETURN MORE THAN ONE PIECE OF INFORMATION
return low, high returns one tuple containing two values. The caller can unpack it into two names, just as you unpacked coordinates in Section 3. The number of names must match this tuple’s size.
This is useful for closely related results, such as a minimum and maximum. Keep the contract clear so the caller knows their order. Returning a collection is different from printing two values or maintaining hidden global variables.
def starting_bounds():
return 1, 20
minimum, maximum = starting_bounds()
print(minimum, maximum)EXPECTED OUTPUT
1 20
09 | WATCH A RESULT TRAVEL BACK
Follow the fixed Python model below. It shows the caller value, the local parameter, the multiplication and the returned result. It models this function rather than running arbitrary Python.
10 | BUILD A SMALL, TESTABLE CONTRACT
Write a calculation function with a meaningful name and return value. First call it with a known number and predict the result. Then try zero and a negative number if the mathematical operation allows them.
Keep input() and print() in the caller for this exercise. A function that receives values is easier to test repeatedly because it does not pause to ask for a response. A calculation function can still be used by a program that collects input first.
Before moving on, explain these four steps: execute the definition, call the function, execute its body and use the return value. If a result unexpectedly becomes None, inspect the function’s return routes and whether you stored the result of a printing operation.
PUT YOUR SKILLS TO WORK
Use the Section 4 challenges to practise these ideas independently. Work in your Python editor, predict results and keep a short test record.
Section 4 challenges Python course navigation