Python functions parameters return guide FP1 examples

Python functions — stop repeating code once and for all

Python functions are the tool that transforms messy code into organised, reusable code. Until now every program you wrote was a sequence of instructions that ran from top to bottom, once. Functions let you name a block of code and reuse it whenever you need it, without copying and pasting. This is one of the most important concepts in FP1 and the foundation of everything you’ll write from here on.

What are Python functions?

A function is a named block of code that performs a specific task and can be called as many times as needed from anywhere in the program.

You’ve already been using functions without realising it. print(), input(), len(), range(), int(), round() — all of these are functions. The difference is that those are built into Python. Now you’ll create your own.

Why use functions?

Imagine you need to calculate the average of a list of grades in five different places in your program. Without functions you’d copy and paste the same three lines of code five times. If you later find a bug in that calculation you’d have to fix it in five places.

With a function you write it once and call it five times. If there’s a bug you fix it in one place:

# Without functions — repeated code
grades1 = [7.5, 8.0, 6.5]
total1 = sum(grades1)
average1 = total1 / len(grades1)
print(f"Group 1 average: {average1}")

grades2 = [9.0, 5.5, 7.0]
total2 = sum(grades2)
average2 = total2 / len(grades2)
print(f"Group 2 average: {average2}")

# With functions — write once, use everywhere
def calculate_average(grades):
    return sum(grades) / len(grades)

print(f"Group 1 average: {calculate_average([7.5, 8.0, 6.5])}")
print(f"Group 2 average: {calculate_average([9.0, 5.5, 7.0])}")

How to define a function

The syntax to create a function in Python:

def function_name(parameters):
    code_block
    return value    # optional
  • def — keyword that tells Python “I’m defining a function”
  • function_name — the name you give the function. Same rules as variables: lowercase, no spaces, use underscores
  • (parameters) — the inputs the function receives. Can be empty: ()
  • : — mandatory colon, same as if and for
  • indented block — the code that belongs to the function
  • return — the value the function sends back. Optional — if there’s no return the function returns None

The simplest function — no parameters, no return

def print_separator():
    print("=" * 30)

# Call it
print_separator()
print("Results")
print_separator()

Output:

==============================
Results
==============================

The function does something (prints) but doesn’t receive anything and doesn’t return anything. Notice that def print_separator(): defines the function but doesn’t execute it. The function only runs when you call it with print_separator().

Functions with parameters

Parameters are the inputs a function receives, values you pass when calling it:

def greet(name):
    print(f"Hello, {name}!")

greet("Sergio")    # → Hello, Sergio!
greet("María")     # → Hello, María!
greet("Carlos")    # → Hello, Carlos!

name is the parameter, inside the function it works like a variable. When you call greet("Sergio"), name takes the value "Sergio". When you call greet("María"), name takes "María".

Multiple parameters:

def describe_student(name, age, degree):
    print(f"{name} is {age} years old and studies {degree}")

describe_student("Sergio", 20, "GCID")
# → Sergio is 20 years old and studies GCID

Functions with return

When a function needs to give back a result you use return:

def square(n):
    return n * n

result = square(5)
print(result)        # → 25
print(square(3))     # → 9
print(square(4) + square(3))    # → 25

return does two things: it sends the value back to wherever the function was called from, and it exits the function immediately no code after return runs in that call.

A function can have multiple return statements it returns from the first one it reaches:

def classify_grade(grade):
    if grade >= 9:
        return "Outstanding"
    elif grade >= 7:
        return "Merit"
    elif grade >= 5:
        return "Passed"
    else:
        return "Failed"

print(classify_grade(8.5))    # → Merit
print(classify_grade(4.0))    # → Failed

Default parameters

You can give parameters a default value, if the caller doesn’t provide that argument it uses the default:

def power(base, exponent=2):    # exponent defaults to 2
    return base ** exponent

print(power(5))       # → 25   (5² — uses default exponent)
print(power(5, 3))    # → 125  (5³ — overrides default)
print(power(2, 10))   # → 1024 (2¹⁰)

Default parameters must come after non-default ones:

# WRONG
def power(exponent=2, base):   # SyntaxError
    ...

# RIGHT
def power(base, exponent=2):   # non-default first
    ...

Functions calling other functions

This is where functions really shine, you can build complex logic by combining simple functions:

def calculate_average(grades):
    if len(grades) == 0:
        return 0
    return sum(grades) / len(grades)

def classify_grade(grade):
    if grade >= 9:   return "Outstanding"
    elif grade >= 7: return "Merit"
    elif grade >= 5: return "Passed"
    else:            return "Failed"

def analyse_group(group_name, grades):
    average = calculate_average(grades)    # calls calculate_average
    classification = classify_grade(average)   # calls classify_grade
    print(f"\n{group_name}:")
    print(f"  Grades:  {grades}")
    print(f"  Average: {round(average, 2)}")
    print(f"  Result:  {classification}")

# Now one call does everything
analyse_group("FP1 Group A", [7.5, 8.0, 6.5, 9.0])
analyse_group("FP1 Group B", [5.5, 4.0, 6.0, 7.5])

Output:

FP1 Group A:
  Grades:  [7.5, 8.0, 6.5, 9.0]
  Average: 7.75
  Result:  Merit

FP1 Group B:
  Grades:  [5.5, 4.0, 6.0, 7.5]
  Average: 5.75
  Result:  Passed

Scope — variables inside functions

Variables defined inside a function only exist inside that function. They’re invisible to the rest of the program:

def my_function():
    x = 10      # local variable — only exists inside the function
    print(x)

my_function()       # → 10
print(x)            # NameError: name 'x' is not defined

This is called scope. Local variables are created when the function is called and destroyed when it returns. This is why you can use the same variable name in different functions without them interfering with each other.

The most common mistakes with functions

Mistake 1 — Confusing defining with calling:

# This only DEFINES the function — doesn't run it
def greet():
    print("Hello")

# This CALLS it — runs it
greet()

Mistake 2 — Forgetting return and using the result:

def add(a, b):
    result = a + b
    # Missing return!

total = add(3, 4)
print(total)    # → None  (not 7)

# Fix
def add(a, b):
    return a + b

Mistake 3 — Modifying a global variable inside a function:

count = 0

def increment():
    count += 1    # UnboundLocalError

# Fix — return the new value instead
def increment(current):
    return current + 1

count = increment(count)

Mistake 4 — Wrong parameter order:

def subtract(a, b):
    return a - b

print(subtract(10, 3))    # → 7
print(subtract(3, 10))    # → -7  (wrong order)

The order of arguments when calling must match the order of parameters in the definition.

Visualise it with Python Tutor

Functions are where pythontutor.com is most valuable. Paste this and step through it:

def square(n):
    result = n * n
    return result

def sum_of_squares(a, b):
    sq_a = square(a)
    sq_b = square(b)
    return sq_a + sq_b

total = sum_of_squares(3, 4)
print(total)

Watch how when sum_of_squares is called a new frame opens. Then when it calls square, another frame opens on top. When square returns, its frame closes and control goes back to sum_of_squares. When sum_of_squares returns, its frame closes and control returns to the main program. That stack of frames is exactly how Python manages function calls.

Quick summary

# DEFINE A FUNCTION
def function_name(param1, param2):
    code_block
    return value    # optional

# CALL A FUNCTION
result = function_name(arg1, arg2)

# WITHOUT PARAMETERS
def print_separator():
    print("=" * 30)
print_separator()

# WITH PARAMETERS
def greet(name, age):
    print(f"Hello {name}, you are {age}")
greet("Sergio", 20)

# WITH RETURN
def square(n):
    return n * n
result = square(5)    # → 25

# DEFAULT PARAMETERS
def power(base, exponent=2):
    return base ** exponent
power(5)      # → 25 (uses default)
power(5, 3)   # → 125 (overrides default)

# FUNCTIONS CALLING FUNCTIONS
def average(grades):
    return sum(grades) / len(grades)

def classify(grade):
    if grade >= 5: return "Passed"
    else: return "Failed"

def analyse(grades):
    avg = average(grades)    # calls average
    cls = classify(avg)      # calls classify
    return avg, cls

# SCOPE
def my_function():
    x = 10    # local — only exists inside
print(x)      # NameError — x doesn't exist outside

# COMMON ERRORS
# 1. Define ≠ call — def only defines, () calls
# 2. Missing return → function returns None
# 3. count += 1 inside function → UnboundLocalError
# 4. Wrong argument order → wrong result, no error

In the next article we practice Python functions with real programs in VS Code.

Similar Posts

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *