Python Foundations · Day 5

Functions: Writing Reusable Code

What you will cover

Why functions matter, def and return, parameters and arguments, default values, keyword arguments, *args/**kwargs, scope, lambdas and docstrings.

How to use this day

Plan about 2 hours. Reimplement examples from memory and write at least one extra function per section.

DAY 5 - Functions: Writing Reusable Code

5.1 Why Functions Matter

Imagine you need to calculate a discounted price in twenty different places in your programme. Without functions, you copy the same logic twenty times. When the discount rate changes, you update it twenty times - and probably miss one. This violates the DRY principle: Don't Repeat Yourself.

A function is a named, reusable block of code. You write it once and call it wherever you need it.

5.2 Defining and Calling Functions

def greet():
    print("Hello! Welcome to Luxley Digital College.")

greet()   # calling the function
greet()   # calling it again

The keyword def declares a function. The function name follows the same naming rules as variables (snake_case). The body is indented.

5.3 Parameters and Arguments

Parameters are variables listed in the function definition. Arguments are the actual values passed when calling the function.

def greet_user(name):           # 'name' is a parameter
    print(f"Hello, {name}!")

greet_user("Alice")             # 'Alice' is an argument
greet_user("Bob")

Multiple parameters

def calculate_bmi(weight_kg, height_m):
    bmi = weight_kg / (height_m ** 2)
    return round(bmi, 1)

result = calculate_bmi(70, 1.75)
print(f"BMI: {result}")   # BMI: 22.9

5.4 The return Statement

return sends a value back to the caller. Without return, a function implicitly returns None.

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

total = add(3, 7)   # total = 10
print(total + 5)    # 15 - we can use the returned value

A function can return multiple values as a tuple:

def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9, 2, 7])
print(f"Min: {low}, Max: {high}")   # Min: 1, Max: 9

5.5 Default Parameters

You can provide default values for parameters. If the caller does not provide that argument, the default is used:

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

print(power(5))      # 25  - uses default exponent of 2
print(power(5, 3))   # 125 - overrides default

Parameters with defaults must come after parameters without defaults:def func(a, b=2) is valid; def func(a=1, b) is not.

5.6 Keyword Arguments

When calling a function, you can specify arguments by name. This makes code more readable and allows you to pass arguments in any order:

def create_profile(name, age, city="London"):
    print(f"{name}, {age}, {city}")

create_profile("Alice", 28)
create_profile(age=32, name="Bob", city="Manchester")
create_profile("Charlie", city="Edinburgh", age=25)

5.7 *args and **kwargs

Sometimes you do not know in advance how many arguments a function will receive.

*args - variable positional arguments

The * collects extra positional arguments into a tuple:

def total(*numbers):
    return sum(numbers)

print(total(1, 2, 3))           # 6
print(total(10, 20, 30, 40))    # 100

**kwargs - variable keyword arguments

** collects extra keyword arguments into a dictionary:

def print_info(**details):
    for key, value in details.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=28, city="London")

You will encounter *args and **kwargs frequently in library source code and documentation.

5.8 Variable Scope

A variable defined inside a function exists only within that function. This is called local scope:

def my_function():
    local_var = "I only exist inside this function."
    print(local_var)

my_function()
print(local_var)   # NameError - local_var does not exist here

Variables defined outside any function have global scope and can be read (but not modified) inside a function:

company = "Luxley Digital"

def show_company():
    print(company)   # reads the global variable - fine

show_company()   # Luxley Digital

To modify a global variable inside a function, use the global keyword - but do this sparingly, as it makes code harder to reason about:

counter = 0

def increment():
    global counter
    counter += 1

increment()
increment()
print(counter)   # 2

5.9 Lambda Functions

A lambda is a small, anonymous function defined in a single line. It is used for short operations that are passed as arguments to other functions:

# Regular function
def square(x):
    return x ** 2

# Equivalent lambda
square = lambda x: x ** 2

print(square(5))   # 25

Lambdas shine when used with sorted(), map() and filter():

students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]

# Sort by score (second element of each tuple)
sorted_students = sorted(students, key=lambda s: s[1], reverse=True)
print(sorted_students)
# [('Bob', 92), ('Alice', 85), ('Charlie', 78)]

5.10 Docstrings

A docstring is a string at the very start of a function that documents what it does. It is not a comment - it is accessible at runtime via help().

def calculate_discount(price, discount_pct):
    """
    Calculate the final price after applying a percentage discount.

    Parameters:
        price (float): The original price.
        discount_pct (float): Discount percentage (e.g., 10 for 10%).

    Returns:
        float: The discounted price, rounded to 2 decimal places.
    """
    return round(price * (1 - discount_pct / 100), 2)

help(calculate_discount)   # displays the docstring

Write docstrings for every function you create from this point forward. Your future self will thank you.

✏️ Day 5 Exercises

Exercise 5.1 - Temperature Converter

Write a function celsius_to_fahrenheit(celsius) and a function fahrenheit_to_celsius(fahrenheit). Then write a third function convert_temperature(value, unit) where unit is either "C" or "F", and it calls the appropriate converter. Test it with 20°C, 98.6°F, 0°C, 212°F.

Formulae: F = (C × 9/5) + 32 and C = (F − 32) × 5/9.

Hint: use an if/elif in convert_temperature to decide which sub-function to call. Round results to 2 decimal places.

Exercise 5.2 - Basic Data Cleaning Function

Write a function clean_string(text) that:

  1. Strips leading and trailing whitespace.
  2. Converts to Title Case.
  3. Replaces multiple internal spaces with a single space.

Then write a second function clean_dataset(data) that takes a list of strings and returns a new list with every string cleaned. Test data:

raw = ["  alice   smith  ", "BOB    JONES", "   charlie   brown   "]

Hint: for step 3, you can use " ".join(text.split()) - .split() without arguments splits on any whitespace and ignores extras, then " ".join(...) reassembles with single spaces.

Exercise 5.3 - Statistics Functions

Without using any imports, write the following functions from scratch:

  1. mean(numbers) - returns the arithmetic mean.
  2. variance(numbers) - returns the population variance.
  3. std_dev(numbers) - returns the population standard deviation (use x ** 0.5).

Formulae:

  • Mean: sum of values ÷ count
  • Variance: mean of squared differences from the mean
  • Standard deviation: √variance

Hint: variance can call mean. std_dev can call variance.

Exercise 5.4 - Challenge: Flexible Report Generator

Write a function generate_report(**data) that accepts any number of keyword arguments and prints them as a formatted report. Include a separator line, a title if a "title" key is present, and all other key-value pairs below it.

Example call:

generate_report(title="Q1 Sales", region="North", total=125000, growth="12%")

Expected output:

==============================
REPORT: Q1 Sales
------------------------------
region   : North
total    : 125000
growth   : 12%
==============================

Hint: use data.pop("title", "Untitled") to extract the title before looping over the remaining items.

📌 Day 5 Summary

ConceptWhat you learned
defDeclare a function
Parameters & argumentsInputs to a function
returnSend a value back to the caller
Default parametersFallback values when arguments are omitted
Keyword argumentsPass arguments by name
*args / **kwargsVariable-length argument lists
ScopeLocal vs global variables
LambdaAnonymous, single-expression functions
DocstringsDocumentation embedded in the function

Tomorrow you will read and write files, handle errors gracefully, and learn to use Python's standard library - turning your programmes into tools that interact with the real world.