This chapter covers functions, reusable blocks of code that perform specific tasks. Functions help you organize code, avoid repetition, and make your programs more readable and maintainable.
Functions are like mini-programs within your program. They take input (parameters), perform operations, and can return output (return values).
You define a function using the def keyword:
def greet():
print("Hello, world!")
greet() # Call the function
Parameters allow functions to accept input:
def greet_person(name):
print(f"Hello, {name}!")
greet_person("Alice")
greet_person("Bob")
def add_numbers(a, b):
return a + b
result = add_numbers(3, 5)
print(result) # 8
You can provide default values for parameters:
def greet_person(name, greeting="Hello"):
print(f"{greeting}, {name}!")
greet_person("Alice") # Hello, Alice!
greet_person("Bob", "Hi") # Hi, Bob!
The return statement sends a value back to the caller:
def square(number):
return number * number
result = square(4)
print(result) # 16
Functions can return multiple values as a tuple:
def divide_and_remainder(dividend, divisor):
quotient = dividend // divisor
remainder = dividend % divisor
return quotient, remainder
q, r = divide_and_remainder(17, 5)
print(f"Quotient: {q}, Remainder: {r}") # Quotient: 3, Remainder: 2
Variables defined inside a function are local to that function:
global_variable = "Accessible everywhere"
def my_function():
local_variable = "Only accessible inside this function"
print(local_variable) # Works
print(global_variable) # Works
my_function()
print(global_variable) # Works
# print(local_variable) # Error - not defined
Docstrings document what your function does:
def calculate_area(length, width):
"""
Calculate the area of a rectangle.
Parameters:
length (float): The length of the rectangle
width (float): The width of the rectangle
Returns:
float: The area of the rectangle
"""
return length * width
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
if y != 0:
return x / y
else:
return "Error: Division by zero"
# Using the functions
result = add(10, 5)
print(f"10 + 5 = {result}")
result = multiply(3, 4)
print(f"3 * 4 = {result}")
def factorial(n):
"""
Calculate the factorial of a number using recursion.
Parameters:
n (int): A non-negative integer
Returns:
int: The factorial of n
"""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n-1)
print(factorial(5)) # 120
print(factorial(0)) # 1
Lambda functions are small, anonymous functions:
# Regular function
def square(x):
return x ** 2
# Same function as lambda
square_lambda = lambda x: x ** 2
print(square(5)) # 25
print(square_lambda(5)) # 25
# Lambda with multiple parameters
add = lambda x, y: x + y
print(add(3, 4)) # 7
Recursion occurs when a function calls itself. It's useful for problems that can be broken down into smaller, similar problems:
def factorial(n):
"""Calculate factorial using recursion."""
if n == 0 or n == 1:
return 1
else:
return n * factorial(n-1)
def fibonacci(n):
"""Calculate nth Fibonacci number."""
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
print(factorial(5)) # 120
print(fibonacci(7)) # 13
Note: Recursion can be elegant but may cause stack overflow for large inputs. For deep recursion, consider iterative approaches.
Decorators modify the behavior of functions without changing their code:
def uppercase_result(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
if isinstance(result, str):
return result.upper()
return result
return wrapper
@uppercase_result
def greet(name):
return f"Hello, {name}!"
print(greet("Alice")) # HELLO, ALICE!
Use *args for variable positional arguments and **kwargs for keyword arguments:
def flexible_function(*args, **kwargs):
print("Positional args:", args)
print("Keyword args:", kwargs)
flexible_function(1, 2, 3, name="Alice", age=30)
# Positional args: (1, 2, 3)
# Keyword args: {'name': 'Alice', 'age': 30}
import pdb
def problematic_function(n):
pdb.set_trace() # Start debugger here
if n > 5:
result = n * 2
else:
result = n + 10
return result
# Using print for simple debugging
def debug_multiply(a, b):
print(f"Debug: a={a}, b={b}")
result = a * b
print(f"Debug: result={result}")
return result
This chapter covered functions in detail, including creation, parameters, return values, scope, documentation, recursion, decorators, and debugging techniques. Functions are essential for writing readable, maintainable, and reusable code.
def keyword and can have parameters and return valuesInteractive Quiz: This chapter comes with a free online quiz to test your understanding of Python functions.