Chapter 4: Functions
Functions are reusable blocks of code designed to perform a specific task. They help organize code, reduce repetition, and improve readability and maintainability. In Python, functions are first-class objects, meaning they can be passed around as arguments, returned from other functions, and assigned to variables.
Defining and Calling Functions
A function must be defined before it can be called. Use the def
keyword to define a function. Functions can take inputs, perform tasks, and optionally return outputs.
Syntax:
def function_name(parameters):
"""Optional documentation string (docstring)"""
# Code block
return value # Optional
Example:
def greet(name):
"""This function returns a greeting message."""
return f"Hello, {name}!"
# Calling the function
greeting = greet("Alice")
print(greeting)
Key Points:
Function names should follow the same naming rules as variables.
Parameters are optional; a function can take zero or more arguments.
The
return
statement is optional but allows the function to send a result back to the caller.Include a docstring to describe the function’s purpose and behavior.
Parameters and Arguments
Types of Parameters:
Positional Parameters: Must be provided in the order they appear in the function definition.
def multiply(a, b): return a * b print(multiply(2, 3)) # Output: 6
Default Parameters: Provide default values for arguments, making them optional.
def greet(name="Guest"): print(f"Hello, {name}!") greet() # Output: Hello, Guest! greet("Alice") # Output: Hello, Alice!
Keyword Arguments: Allow specifying arguments by name, regardless of their order.
def divide(numerator, denominator): return numerator / denominator print(divide(denominator=4, numerator=8)) # Output: 2.0
Arbitrary Arguments: Use
*args
for non-keyword variable-length arguments and**kwargs
for keyword variable-length arguments.def print_all(*args, **kwargs): print("Positional:", args) print("Keyword:", kwargs) print_all(1, 2, 3, a="apple", b="banana") # Positional: (1, 2, 3) # Keyword: {'a': 'apple', 'b': 'banana'}
Return Values
A function can return a value to the caller using the return
statement. If no return
is provided, the function implicitly returns None
.
Examples:
def square(num):
return num ** 2
print(square(4)) # Output: 16
# Multiple return values
def stats(numbers):
return min(numbers), max(numbers), sum(numbers) / len(numbers)
print(stats([1, 2, 3, 4, 5])) # Output: (1, 5, 3.0)
Scope and Lifetime of Variables
Scope determines where a variable can be accessed, while lifetime refers to how long it exists.
Types of Scope:
Local Scope: Variables declared inside a function are accessible only within that function.
def test(): x = 10 # Local variable print(x) test() # print(x) # Error: x is not defined
Global Scope: Variables declared outside all functions are accessible everywhere.
x = 10 # Global variable def test(): print(x) test() print(x)
Global Keyword: Used to modify a global variable inside a function.
x = 10 def modify(): global x x = 20 modify() print(x) # Output: 20
Lifetime:
Local variables are destroyed when the function execution ends.
Global variables persist throughout the program’s execution.
Lambda Functions
Lambda functions are anonymous, single-line functions defined using the lambda
keyword. They are useful for short, simple operations.
Syntax:
lambda arguments: expression
Examples:
# Single-argument lambda
square = lambda x: x ** 2
print(square(5)) # Output: 25
# Multi-argument lambda
add = lambda a, b: a + b
print(add(3, 7)) # Output: 10
# Sorting with lambda
names = ["Alice", "Bob", "Charlie"]
names.sort(key=lambda name: len(name))
print(names) # Output: ['Bob', 'Alice', 'Charlie']
Key Points:
Lambda functions can have multiple arguments but only one expression.
They are often used with higher-order functions like
map()
,filter()
, andreduce()
.
Higher-Order Functions
Functions that accept other functions as arguments or return them as results are called higher-order functions.
Examples:
# Using map()
numbers = [1, 2, 3, 4]
squares = map(lambda x: x ** 2, numbers)
print(list(squares)) # Output: [1, 4, 9, 16]
# Using filter()
numbers = [1, 2, 3, 4]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens)) # Output: [2, 4]
# Using reduce()
from functools import reduce
numbers = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, numbers)
print(product) # Output: 24
Best Practices
Use meaningful names for functions and parameters.
Keep functions short and focused on a single task.
Document functions with docstrings.
Avoid using global variables; prefer passing arguments to functions.
Test functions independently.
Exercises
Exercise 1:
Write a function that calculates the greatest common divisor (GCD) of two numbers.
Solution:
def gcd(a, b):
while b:
a, b = b, a % b
return a
print(gcd(48, 18)) # Output: 6
Exercise 2:
Write a function to generate the Fibonacci sequence up to a given number n
.
Solution:
def fibonacci(n):
sequence = []
a, b = 0, 1
while a < n:
sequence.append(a)
a, b = b, a + b
return sequence
print(fibonacci(10)) # Output: [0, 1, 1, 2, 3, 5, 8]
Exercise 3:
Write a function that accepts another function as an argument and applies it to a list of numbers.
Solution:
def apply_function(func, numbers):
return [func(num) for num in numbers]
print(apply_function(lambda x: x ** 2, [1, 2, 3, 4])) # Output: [1, 4, 9, 16]
In the next chapter, we will explore Python’s data structures, including lists, tuples, dictionaries, and sets.
Last updated