Advanced Function Design
Decorators: Enhancing Function Behavior
Decorators allow dynamic modification of function behavior without changing the function's source code:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} completed")
return result
return wrapper
@log_decorator
def calculate_sum(a, b):
return a + b
result = calculate_sum(5, 3) ## Demonstrates decorator usage
Lambda Functions: Inline Anonymous Functions
## Compact function definition
multiply = lambda x, y: x * y
print(multiply(4, 5)) ## Output: 20
## Using lambda with built-in functions
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))
Higher-Order Functions
graph TD
A[Higher-Order Functions] --> B[Accept Functions as Arguments]
A --> C[Return Functions]
B --> D[map()]
B --> E[filter()]
C --> F[Function Factories]
Function Composition Example
def compose(f, g):
return lambda x: f(g(x))
def double(x):
return x * 2
def increment(x):
return x + 1
composed_func = compose(double, increment)
print(composed_func(3)) ## Output: 8
Closures and Function Factories
def create_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5)) ## Output: 10
print(triple(5)) ## Output: 15
Generator Functions
| Feature |
Description |
Example |
| Lazy Evaluation |
Generates values on-the-fly |
Memory efficient |
| Iteration |
Can be iterated multiple times |
Saves computation |
| Yield Keyword |
Pauses and resumes function |
Maintains state |
def fibonacci_generator(n):
a, b = 0, 1
count = 0
while count < n:
yield a
a, b = b, a + b
count += 1
fib_seq = list(fibonacci_generator(6))
print(fib_seq) ## Output: [0, 1, 1, 2, 3, 5]
Recursive Functions
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) ## Output: 120
Error Handling in Advanced Functions
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "Cannot divide by zero"
except TypeError:
return "Invalid input types"
print(safe_divide(10, 2)) ## Output: 5.0
print(safe_divide(10, 0)) ## Output: Cannot divide by zero
Advanced Type Hinting
from typing import Callable, List, Optional
def apply_operation(
numbers: List[int],
operation: Callable[[int], int]
) -> List[int]:
return [operation(num) for num in numbers]
def square(x: int) -> int:
return x ** 2
result = apply_operation([1, 2, 3, 4], square)
print(result) ## Output: [1, 4, 9, 16]
Conclusion
Advanced function design techniques in Python, as demonstrated by LabEx, enable more flexible, efficient, and elegant code implementations.