Python Functions Practice: 15 Core Exercises with Solutions

Master Python user-defined functions (UDF) with this curated collection of 15 hands-on practice problems covering syntax, parameters, variable scope, closures, lambda expressions, and recursion.

Structured Learning Problem Set: Each exercise features an interactive collapsible solution toggle, syntax-highlighted code, dedicated terminal output, and technical architectural notes. Deepen your understanding of local and global variable scope, recursive algorithms, anonymous lambda functions, and Python's built-in functions.

Part 1: Basic Definition, Parameters & Arguments (Questions 1 to 4) 🔝

  1. Question 1: Define a function greet(name) that prints a personalized greeting with an optional default value.
    def greet(name='Guest'):
        print(f'Hello, {name}!')
    
    greet('Alex')
    greet()

    Terminal Output:

    Hello, Alex!
    Hello, Guest!
  2. Question 2: Demonstrate positional vs. keyword arguments in a function describe_pet(animal, name).
    def describe_pet(animal, name):
        print(f'I have a {animal} named {name}.')
    
    # Positional arguments
    describe_pet('dog', 'Buddy')
    # Keyword arguments (order independent)
    describe_pet(name='Whiskers', animal='cat')

    Terminal Output:

    I have a dog named Buddy.
    I have a cat named Whiskers.
  3. Question 3: Write a function sum_all(*numbers) that sums an arbitrary number of numeric arguments.
    def sum_all(*numbers):
        total = 0
        for n in numbers:
            total += n
        return total
    
    print('Sum 3 items: ', sum_all(10, 20, 30))
    print('Sum 5 items: ', sum_all(1, 2, 3, 4, 5))

    Terminal Output:

    Sum 3 items:  60
    Sum 5 items:  15
  4. Question 4: Write a function build_profile(first, last, **user_info) accepting arbitrary keyword arguments.
    def build_profile(first, last, **user_info):
        profile = {'first_name': first, 'last_name': last}
        profile.update(user_info)
        return profile
    
    user = build_profile('Alex', 'Ronald', role='Admin', dept='IT')
    print(user)

    Terminal Output:

    {'first_name': 'Alex', 'last_name': 'Ronald', 'role': 'Admin', 'dept': 'IT'}

Part 2: Return Values, Mutability & Type Hinting (Questions 5 to 8) 🔝

  1. Question 5: Write a function get_min_max(numbers) returning both minimum and maximum as an unpacked tuple.
    def get_min_max(numbers):
        return min(numbers), max(numbers)
    
    low, high = get_min_max([15, 3, 89, 42, 7])
    print('Lowest: ', low)
    print('Highest:', high)

    Terminal Output:

    Lowest:  3
    Highest: 89
  2. Question 6: Demonstrate early return by writing find_first_even(numbers) which halts at the first even match.
    def find_first_even(numbers):
        for num in numbers:
            if num % 2 == 0:
                return num  # Early exit
        return None
    
    print('First even:', find_first_even([1, 3, 7, 8, 11]))
    print('No even:   ', find_first_even([1, 3, 5]))

    Terminal Output:

    First even: 8
    No even:    None
  3. Question 7: Write a pure function remove_negatives(numbers) returning a new list without mutating the original.
    def remove_negatives(numbers):
        return [x for x in numbers if x >= 0]
    
    raw_data = [10, -5, 20, -1, 30]
    clean_data = remove_negatives(raw_data)
    print('Original untouched:', raw_data)
    print('Cleaned output:    ', clean_data)

    Terminal Output:

    Original untouched: [10, -5, 20, -1, 30]
    Cleaned output:     [10, 20, 30]
  4. Question 8: Define calculate_bmi(weight_kg, height_m) using Python type hints and a docstring.
    def calculate_bmi(weight_kg: float, height_m: float) -> float:
        """Calculates Body Mass Index (BMI) using weight and height."""
        return round(weight_kg / (height_m ** 2), 2)
    
    bmi = calculate_bmi(70.0, 1.75)
    print('BMI Value:  ', bmi)
    print('Docstring:  ', calculate_bmi.__doc__)

    Terminal Output:

    BMI Value:   22.86
    Docstring:   Calculates Body Mass Index (BMI) using weight and height.

Part 3: Variable Scope, Closures & Default Traps (Questions 9 to 12) 🔝

  1. Question 9: Demonstrate variable shadowing where a local variable inside a function masks an outer global variable.
    x = 100  # Global variable
    
    def shadow_demo():
        x = 200  # Local variable shadowing global x
        print('Inside function: ', x)
    
    shadow_demo()
    print('Outside function:', x)

    Terminal Output:

    Inside function:  200
    Outside function: 100
  2. Question 10: Use the global keyword to modify a module-level variable from inside a function.
    counter = 0
    
    def increment():
        global counter
        counter += 1
    
    increment()
    increment()
    print('Global counter:', counter)

    Terminal Output:

    Global counter: 2
  3. Question 11: Use the nonlocal keyword in nested functions to modify a variable in the enclosing outer scope.
    def make_counter():
        count = 0
        def step():
            nonlocal count
            count += 1
            return count
        return step
    
    c = make_counter()
    print('Step 1:', c())
    print('Step 2:', c())

    Terminal Output:

    Step 1: 1
    Step 2: 2
  4. Question 12: Identify the mutable default argument trap (lst=[]) and fix it using None.
    # Problem: lst=[] retains state across separate calls!
    # Fix: use default None and initialize inside
    def safe_append(item, target_list=None):
        if target_list is None:
            target_list = []
        target_list.append(item)
        return target_list
    
    print('Call 1:', safe_append('A'))
    print('Call 2:', safe_append('B'))

    Terminal Output:

    Call 1: ['A']
    Call 2: ['B']

Part 4: Recursion, Lambdas & Higher-Order Functions (Questions 13 to 15) 🔝

  1. Question 13: Write a recursive function factorial(n) with an explicit base case and recursive step.
    def factorial(n):
        if n <= 1:  # Base case
            return 1
        return n * factorial(n - 1)  # Recursive step
    
    print('Factorial 5:', factorial(5))
    print('Factorial 0:', factorial(0))

    Terminal Output:

    Factorial 5: 120
    Factorial 0: 1
  2. Question 14: Sort a list of student (name, score) tuples by score using an anonymous lambda function.
    students = [('Alex', 82), ('Sarah', 95), ('Ronald', 74), ('John', 88)]
    # Sort ascending by score (item[1])
    students.sort(key=lambda s: s[1])
    print('Sorted by score:', students)

    Terminal Output:

    Sorted by score: [('Ronald', 74), ('Alex', 82), ('John', 88), ('Sarah', 95)]
  3. Question 15: Write a recursive function flatten(nested) that flattens an arbitrarily nested list structure.
    def flatten(nested_list):
        flat = []
        for item in nested_list:
            if isinstance(item, list):
                flat.extend(flatten(item))  # Recurse
            else:
                flat.append(item)
        return flat
    
    matrix = [1, [2, [3, 4], 5], [6, 7]]
    print('Flattened list:', flatten(matrix))

    Terminal Output:

    Flattened list: [1, 2, 3, 4, 5, 6, 7]

Interactive Notebook & Practice Exercises 🔝

Work through all 15 practice questions, explore variable scoping, and execute recursion traces in our interactive companion Jupyter Notebook:

Interactive Companion Jupyter Notebook

Explore interactive code cells for all 15 function challenges, test default parameter behaviors, inspect closures, and run self-validating assertions.

View on GitHub Run in Google Colab

Frequently Asked Questions (FAQ) 🔝

What is the difference between *args and **kwargs?

*args collects arbitrary extra positional arguments as a tuple, while **kwargs collects extra keyword arguments as a dictionary.

Why should I avoid mutable default arguments like def fn(lst=[])?

Default argument expressions are evaluated once at function definition time, not upon each call. Reusing a mutable default shares the same list across invocations. Always default to None instead.

What is the difference between global and nonlocal?

global binds a variable name to the top-level module scope, while nonlocal binds to the nearest enclosing non-global scope (useful in nested functions and closures).

When should I use a lambda function?

Use lambda for short, single-expression anonymous callbacks (such as key extractors in sorted(), min(), or max()). For complex logic, use standard def functions.

Further Reading & Related Tutorials 🔝




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer