Module 16 - Functional Programming
Functional programming treats computation as the evaluation of mathematical functions and avoids changing state. Python supports functional programming through lambda functions, map, filter, reduce, and higher-order functions.
1. Lambda Functions
Lambda functions are anonymous, one-line functions defined using the lambda keyword.
Syntax
lambda arguments: expression
Basic Examples
# Regular function
def square(x):
return x ** 2
# Lambda equivalent
square = lambda x: x ** 2
print(square(5)) # 25
# Multiple arguments
add = lambda x, y: x + y
print(add(3, 7)) # 10
# No arguments
get_pi = lambda: 3.14159
print(get_pi()) # 3.14159
Common Use Cases
# Sorting with custom key
students = [
{'name': 'Alice', 'grade': 88},
{'name': 'Bob', 'grade': 95},
{'name': 'Charlie', 'grade': 82}
]
# Sort by grade
sorted_students = sorted(students, key=lambda s: s['grade'])
print(sorted_students)
# Sort strings by length
words = ['python', 'is', 'awesome']
sorted_words = sorted(words, key=lambda w: len(w))
print(sorted_words) # ['is', 'python', 'awesome']
Use lambda for simple, one-time operations. For complex logic or reusable functions, use def for better readability.
2. The map() Function
map() applies a function to every item in an iterable and returns an iterator.
Syntax
map(function, iterable)
Examples
# Square all numbers
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# Convert strings to integers
str_nums = ['1', '2', '3', '4']
int_nums = list(map(int, str_nums))
print(int_nums) # [1, 2, 3, 4]
# Multiple iterables
a = [1, 2, 3]
b = [10, 20, 30]
result = list(map(lambda x, y: x + y, a, b))
print(result) # [11, 22, 33]
# Using with regular functions
def celsius_to_fahrenheit(c):
return (c * 9/5) + 32
temps_c = [0, 10, 20, 30, 40]
temps_f = list(map(celsius_to_fahrenheit, temps_c))
print(temps_f) # [32.0, 50.0, 68.0, 86.0, 104.0]
Map vs List Comprehension
numbers = [1, 2, 3, 4, 5]
# Using map
squared_map = list(map(lambda x: x**2, numbers))
# Using list comprehension (more Pythonic)
squared_comp = [x**2 for x in numbers]
# Both produce: [1, 4, 9, 16, 25]
3. The filter() Function
filter() creates an iterator containing only items for which the function returns True.
Syntax
filter(function, iterable)
Examples
# Filter even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# Filter positive numbers
values = [-5, -2, 0, 3, 7, -1, 9]
positives = list(filter(lambda x: x > 0, values))
print(positives) # [3, 7, 9]
# Filter strings by length
words = ['hi', 'hello', 'hey', 'goodbye', 'yo']
long_words = list(filter(lambda w: len(w) > 3, words))
print(long_words) # ['hello', 'goodbye']
# Filter None values
data = [1, None, 3, None, 5]
clean_data = list(filter(None, data)) # None as function
print(clean_data) # [1, 3, 5]
Filter vs List Comprehension
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Using filter
evens_filter = list(filter(lambda x: x % 2 == 0, numbers))
# Using list comprehension (more Pythonic)
evens_comp = [x for x in numbers if x % 2 == 0]
# Both produce: [2, 4, 6, 8, 10]
4. The reduce() Function
reduce() applies a function cumulatively to items in an iterable, reducing it to a single value.
Syntax
from functools import reduce
reduce(function, iterable, [initializer])
Examples
from functools import reduce
# Sum of all numbers
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15
# Product of all numbers
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120
# Find maximum
numbers = [3, 7, 2, 9, 1]
maximum = reduce(lambda x, y: x if x > y else y, numbers)
print(maximum) # 9
# With initial value
numbers = [1, 2, 3]
result = reduce(lambda x, y: x + y, numbers, 10)
print(result) # 16 (10 + 1 + 2 + 3)
# Concatenate strings
words = ['Hello', ' ', 'World', '!']
sentence = reduce(lambda x, y: x + y, words)
print(sentence) # 'Hello World!'
How reduce() Works
# reduce(lambda x, y: x + y, [1, 2, 3, 4])
# Step 1: x=1, y=2 → result=3
# Step 2: x=3, y=3 → result=6
# Step 3: x=6, y=4 → result=10
# Final result: 10
5. Combining Functional Tools
Chaining Operations
from functools import reduce
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Get sum of squares of even numbers
result = reduce(
lambda x, y: x + y,
map(lambda x: x**2,
filter(lambda x: x % 2 == 0, numbers))
)
print(result) # 220 (4 + 16 + 36 + 64 + 100)
# More readable with list comprehension
result = sum(x**2 for x in numbers if x % 2 == 0)
print(result) # 220
Practical Example: Data Processing Pipeline
# Sample data
sales = [
{'product': 'Laptop', 'price': 1000, 'quantity': 2},
{'product': 'Mouse', 'price': 25, 'quantity': 5},
{'product': 'Keyboard', 'price': 75, 'quantity': 3},
{'product': 'Monitor', 'price': 300, 'quantity': 1}
]
# Calculate total revenue for items over $50
total_revenue = reduce(
lambda acc, sale: acc + sale,
map(lambda s: s['price'] * s['quantity'],
filter(lambda s: s['price'] > 50, sales))
)
print(f"Total revenue: ${total_revenue}") # $2525
6. Higher-Order Functions
Functions that take other functions as arguments or return functions.
Functions as Arguments
def apply_operation(x, y, operation):
"""Apply operation to x and y"""
return operation(x, y)
# Different operations
add = lambda x, y: x + y
multiply = lambda x, y: x * y
power = lambda x, y: x ** y
print(apply_operation(5, 3, add)) # 8
print(apply_operation(5, 3, multiply)) # 15
print(apply_operation(5, 3, power)) # 125
Functions Returning Functions
def make_multiplier(n):
"""Return a function that multiplies by n"""
return lambda x: x * n
# Create specific multipliers
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
# Create power functions
def make_power(n):
"""Return a function that raises to power n"""
return lambda x: x ** n
square = make_power(2)
cube = make_power(3)
print(square(4)) # 16
print(cube(4)) # 64
7. Function Composition
Combining multiple functions to create new functions.
def compose(*functions):
"""Compose multiple functions"""
def inner(arg):
result = arg
for func in reversed(functions):
result = func(result)
return result
return inner
# Define simple functions
add_five = lambda x: x + 5
multiply_by_two = lambda x: x * 2
square = lambda x: x ** 2
# Compose functions
f = compose(square, multiply_by_two, add_five)
print(f(3)) # ((3 + 5) * 2) ** 2 = 256
# More practical example
def remove_spaces(s): return s.replace(' ', '')
def to_uppercase(s): return s.upper()
def add_prefix(s): return 'PREFIX_' + s
process_string = compose(add_prefix, to_uppercase, remove_spaces)
result = process_string("hello world")
print(result) # 'PREFIX_HELLOWORLD'
8. Partial Functions
Creating new functions by fixing some arguments of an existing function.
from functools import partial
# Regular function
def power(base, exponent):
return base ** exponent
# Create partial functions
square = partial(power, exponent=2)
cube = partial(power, exponent=3)
print(square(5)) # 25
print(cube(5)) # 125
# More practical example
def log_message(message, level='INFO'):
print(f"[{level}] {message}")
# Create specialized logging functions
log_error = partial(log_message, level='ERROR')
log_warning = partial(log_message, level='WARNING')
log_error("Something went wrong!")
log_warning("Proceed with caution")
9. Comparison Table
| Function | Purpose | Returns | Example |
|---|---|---|---|
map() | Transform items | Iterator of results | map(str.upper, ['a', 'b']) |
filter() | Select items | Iterator of filtered items | filter(lambda x: x > 0, [-1, 2]) |
reduce() | Aggregate to single value | Single value | reduce(lambda x, y: x+y, [1,2,3]) |
lambda | Create anonymous function | Function object | lambda x: x * 2 |
partial() | Fix function arguments | New function | partial(pow, 2) |
10. Functional vs Imperative Style
Imperative (Procedural)
numbers = [1, 2, 3, 4, 5]
result = []
for num in numbers:
if num % 2 == 0:
result.append(num ** 2)
total = 0
for num in result:
total += num
print(total)
Functional
from functools import reduce
numbers = [1, 2, 3, 4, 5]
total = reduce(
lambda x, y: x + y,
map(lambda x: x ** 2,
filter(lambda x: x % 2 == 0, numbers))
)
print(total)
Pythonic (Best)
numbers = [1, 2, 3, 4, 5]
total = sum(x**2 for x in numbers if x % 2 == 0)
print(total)
While functional programming is powerful, prioritize readability. List comprehensions are often more Pythonic than map()/filter().
Summary
✅ Lambda functions create anonymous, one-line functions
✅ map() transforms items in an iterable
✅ filter() selects items based on a condition
✅ reduce() aggregates items to a single value
✅ Higher-order functions enhance code flexibility
✅ Prefer list comprehensions for readability
Next Steps
In Module 17, you'll learn:
- Regular expressions for pattern matching
- The
remodule - Common regex patterns
- Text processing and validation
Practice Exercises
- Use
map()to convert a list of temperatures from Celsius to Fahrenheit - Use
filter()to extract all prime numbers from a list - Use
reduce()to find the longest string in a list - Create a function that composes three mathematical operations
- Build a data processing pipeline using
map(),filter(), andreduce()
Create a function pipeline() that:
- Takes multiple functions as arguments
- Returns a new function that applies them in sequence
- Handles both single values and iterables
- Example:
pipeline(double, add_ten, square)(5)→(5*2+10)²=400