Introduction to Functions

Master the fundamentals of Python functions and learn how to create reusable, efficient code.

45 minutes Beginner Functions

What are Functions?

Understanding Functions

Definition

A function is a reusable block of code that performs a specific task. Functions help organize code, make it more readable, and allow for code reuse.

Explanation

Think of functions like recipes in a cookbook. Each recipe (function) has a name, ingredients (parameters), and steps (code) to create something specific.

# Basic function definition
def greet(name):
    """Return a greeting message."""
    return f"Hello, {name}!"

# Function call
message = greet("Alice")
print(message)  # Output: Hello, Alice!

Function Syntax

How to Define Functions

Definition

Functions in Python are defined using the 'def' keyword, followed by the function name, parameters in parentheses, and a colon.

Explanation

The function definition creates a new function object and assigns it to the function name. The code inside the function only runs when the function is called.

def calculate_area(length, width):
    """
    Calculate the area of a rectangle.
    
    Args:
        length (float): Length of the rectangle
        width (float): Width of the rectangle
        
    Returns:
        float: Area of the rectangle
    """
    return length * width

# Using the function
area = calculate_area(5, 3)
print(f"Area: {area}")  # Output: Area: 15

Function Parameters

Types of Parameters

Definition

Parameters are variables that receive values when a function is called. Python supports different types of parameters: required, default, and variable-length parameters.

Explanation

Parameters make functions flexible and reusable. Required parameters must be provided, default parameters have preset values, and variable-length parameters can accept any number of arguments.

# Required parameters
def add(x, y):
    return x + y

# Default parameters
def greet(name="Guest"):
    return f"Hello, {name}!"

# Variable-length parameters
def sum_all(*args):
    return sum(args)

# Using the functions
print(add(5, 3))           # Output: 8
print(greet())             # Output: Hello, Guest!
print(greet("Alice"))      # Output: Hello, Alice!
print(sum_all(1, 2, 3, 4)) # Output: 10

Return Values

Understanding Return Statements

Definition

The return statement sends a value back to the code that called the function. A function can return any type of data, including multiple values.

Explanation

Return values allow functions to communicate their results back to the calling code. Functions can return single values, multiple values, or no value (None).

# Single return value
def square(number):
    return number ** 2

# Multiple return values
def get_coordinates():
    return 10, 20

# No return value
def print_message(message):
    print(message)
    # Returns None implicitly

# Using the functions
result = square(5)
print(result)  # Output: 25

x, y = get_coordinates()
print(f"Coordinates: ({x}, {y})")  # Output: Coordinates: (10, 20)

Function Documentation

Writing Docstrings

Definition

Docstrings are string literals that appear as the first statement in a function. They provide documentation about the function's purpose, parameters, and return values.

Explanation

Good documentation helps other developers understand how to use your functions. Python's help() function and documentation generators use docstrings to create documentation.

def calculate_total(items, tax_rate=0.1):
    """
    Calculate the total price including tax.
    
    Args:
        items (list): List of item prices
        tax_rate (float): Tax rate as decimal (default: 0.1)
        
    Returns:
        float: Total price with tax
        
    Raises:
        ValueError: If tax_rate is negative
    """
    if tax_rate < 0:
        raise ValueError("Tax rate cannot be negative")
    subtotal = sum(items)
    tax = subtotal * tax_rate
    return subtotal + tax

Function Scope

Understanding Variable Scope

Definition

Scope refers to the visibility and lifetime of variables in a program. Python has local, global, and nonlocal scopes.

Explanation

Variables defined inside a function are local to that function. Global variables are accessible throughout the program. The nonlocal keyword allows access to variables in the outer scope.

# Global variable
x = 10

def my_function():
    # Local variable
    y = 20
    print(f"Inside function: x = {x}, y = {y}")

def modify_global():
    global x
    x = 30
    print(f"Modified global x: {x}")

# Using the functions
my_function()      # Output: Inside function: x = 10, y = 20
modify_global()    # Output: Modified global x: 30
print(f"Global x: {x}")  # Output: Global x: 30

Lambda Functions

Anonymous Functions

Definition

Lambda functions are small anonymous functions that can have any number of arguments but can only have one expression.

Explanation

Lambda functions are useful when you need a simple function for a short period of time. They're often used with built-in functions like map(), filter(), and sorted().

# Basic lambda function
square = lambda x: x ** 2

# Using lambda with map()
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))

# Using lambda with filter()
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))

print(squared)        # Output: [1, 4, 9, 16, 25]
print(even_numbers)   # Output: [2, 4]

Function Arguments

Types of Arguments

Definition

Arguments are the values passed to a function when it is called. Python supports positional, keyword, default, and variable-length arguments.

Explanation

Understanding different types of arguments helps you write more flexible and powerful functions. You can mix different types of arguments in a single function.

def create_profile(name, age, city="Unknown", **kwargs):
    """
    Create a user profile with required and optional information.
    
    Args:
        name (str): User's name
        age (int): User's age
        city (str): User's city (optional)
        **kwargs: Additional user information
    """
    profile = {
        "name": name,
        "age": age,
        "city": city,
        **kwargs
    }
    return profile

# Using different types of arguments
profile1 = create_profile("Alice", 25)
profile2 = create_profile("Bob", 30, "New York", occupation="Developer")
print(profile1)
print(profile2)

Function Decorators

Understanding Decorators

Definition

Decorators are functions that modify the behavior of other functions. They provide a way to add functionality to existing functions without modifying their code.

Explanation

Decorators are powerful tools for code reuse and separation of concerns. They're commonly used for logging, timing, access control, and caching.

def timer(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"Function {func.__name__} took {end - start} seconds")
        return result
    return wrapper

@timer
def slow_function():
    import time
    time.sleep(1)
    return "Done!"

# Using the decorated function
result = slow_function()  # Output: Function slow_function took 1.0 seconds

Best Practices

Writing Good Functions

Definition

Good functions are well-documented, focused on a single task, and follow Python's style guidelines. They should be easy to understand, test, and maintain.

Explanation

Following best practices helps create maintainable and reliable code. This includes proper naming, documentation, error handling, and code organization.

def calculate_statistics(numbers):
    """
    Calculate basic statistics for a list of numbers.
    
    Args:
        numbers (list): List of numbers
        
    Returns:
        dict: Dictionary containing statistics
        
    Raises:
        ValueError: If the list is empty
    """
    if not numbers:
        raise ValueError("List cannot be empty")
        
    return {
        "count": len(numbers),
        "sum": sum(numbers),
        "average": sum(numbers) / len(numbers),
        "minimum": min(numbers),
        "maximum": max(numbers)
    }

# Using the function
try:
    stats = calculate_statistics([1, 2, 3, 4, 5])
    print(stats)
except ValueError as e:
    print(f"Error: {e}")