Functions

Functions are reusable blocks of code that perform a specific task. They help organize your code, make it more readable, and reduce repetition. In this lesson, we'll learn how to define and use functions in Python.

Defining Functions

In Python, you define a function using the def keyword, followed by the function name, parentheses, and a colon. The function body is indented:

def greet():
    print("Hello, World!")

# Call the function
greet()  # Outputs: Hello, World!

Function Parameters

Functions can accept parameters, which are values passed to the function when it's called:

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

# Call the function with an argument
greet("Alice")  # Outputs: Hello, Alice!

Multiple Parameters

def greet(name, age):
    print(f"Hello, {name}! You are {age} years old.")

# Call the function with multiple arguments
greet("Alice", 30)  # Outputs: Hello, Alice! You are 30 years old.

Default Parameter Values

You can specify default values for parameters, which are used if the caller doesn't provide a value:

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

# Call the function with and without the optional argument
greet("Alice")  # Outputs: Hello, Alice!
greet("Bob", "Hi")  # Outputs: Hi, Bob!

Keyword Arguments

You can specify arguments by parameter name, which allows you to provide them in any order:

def greet(name, age):
    print(f"Hello, {name}! You are {age} years old.")

# Call the function with keyword arguments
greet(age=30, name="Alice")  # Outputs: Hello, Alice! You are 30 years old.

Variable-Length Arguments (*args)

You can define a function that accepts a variable number of positional arguments using the *args syntax:

def sum_all(*numbers):
    total = 0
    for num in numbers:
        total += num
    return total

# Call the function with different numbers of arguments
result1 = sum_all(1, 2, 3)  # 6
result2 = sum_all(1, 2, 3, 4, 5)  # 15
print(result1, result2)

Variable-Length Keyword Arguments (**kwargs)

You can define a function that accepts a variable number of keyword arguments using the **kwargs syntax:

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

# Call the function with different keyword arguments
print_info(name="Alice", age=30, city="New York")
# Outputs:
# name: Alice
# age: 30
# city: New York

Return Values

Functions can return values using the return statement:

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

# Call the function and store the result
result = add(3, 5)
print(result)  # Outputs: 8

Multiple Return Values

Functions can return multiple values as a tuple:

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

# Call the function and unpack the returned tuple
minimum, maximum = get_min_max([5, 3, 8, 1, 7])
print(f"Minimum: {minimum}, Maximum: {maximum}")
# Outputs: Minimum: 1, Maximum: 8

Function Scope

Variables defined inside a function have local scope and are only accessible within that function:

def my_function():
    x = 10  # Local variable
    print(x)

my_function()  # Outputs: 10
# print(x)  # This would cause an error because x is not defined in this scope

Global Variables

You can access global variables from within a function:

x = 10  # Global variable

def my_function():
    print(x)  # Accessing global variable

my_function()  # Outputs: 10

Modifying Global Variables

To modify a global variable from within a function, you need to use the global keyword:

x = 10  # Global variable

def modify_global():
    global x
    x = 20  # Modifying global variable

print(x)  # Outputs: 10
modify_global()
print(x)  # Outputs: 20

Lambda Functions

Lambda functions are small, anonymous functions defined using the lambda keyword:

# Regular function
def add(a, b):
    return a + b

# Equivalent lambda function
add_lambda = lambda a, b: a + b

print(add(3, 5))       # Outputs: 8
print(add_lambda(3, 5))  # Outputs: 8

Lambda functions are often used with functions like map(), filter(), and sorted():

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

# Using lambda with filter()
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # Outputs: [2, 4]

# Using lambda with sorted()
students = [
    {"name": "Alice", "grade": 85},
    {"name": "Bob", "grade": 92},
    {"name": "Charlie", "grade": 78}
]
sorted_students = sorted(students, key=lambda student: student["grade"], reverse=True)
for student in sorted_students:
    print(f"{student['name']}: {student['grade']}")

Recursion

Recursion is when a function calls itself. It's useful for solving problems that can be broken down into smaller, similar subproblems:

def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n - 1)

print(factorial(5))  # Outputs: 120 (5 * 4 * 3 * 2 * 1)

Decorators

Decorators are functions that modify the behavior of other functions. They are a powerful feature in Python:

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()
# Outputs:
# Something is happening before the function is called.
# Hello!
# Something is happening after the function is called.

Generators

Generators are functions that can pause and resume their execution. They use the yield keyword instead of return:

def count_up_to(n):
    i = 1
    while i <= n:
        yield i
        i += 1

# Using the generator
counter = count_up_to(5)
for num in counter:
    print(num)
# Outputs:
# 1
# 2
# 3
# 4
# 5

Built-in Functions

Python provides many built-in functions that you can use without importing any modules:

# len() - Returns the length of an object
print(len("Hello"))  # Outputs: 5

# max() and min() - Return the maximum and minimum values
print(max(5, 10, 3))  # Outputs: 10
print(min(5, 10, 3))  # Outputs: 3

# sum() - Returns the sum of all items in an iterable
print(sum([1, 2, 3, 4, 5]))  # Outputs: 15

# sorted() - Returns a sorted list
print(sorted([3, 1, 4, 1, 5, 9, 2]))  # Outputs: [1, 1, 2, 3, 4, 5, 9]

# enumerate() - Returns an enumerate object
for i, value in enumerate(["a", "b", "c"]):
    print(i, value)
# Outputs:
# 0 a
# 1 b
# 2 c

# zip() - Returns an iterator of tuples
for item in zip([1, 2, 3], ["a", "b", "c"]):
    print(item)
# Outputs:
# (1, 'a')
# (2, 'b')
# (3, 'c')

Try experimenting with functions in the code playground below!

Quick Quiz

What keyword is used to define a function in Python?

Code Playground

Code output will appear here...