Practical Closure Patterns
Decorator Pattern
Simple Decorator
def log_function_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_function_call
def add(a, b):
return a + b
result = add(3, 4) ## Logs function call
Parameterized Decorator
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")
Factory Function Pattern
def create_multiplier_function(factor):
def multiplier(x):
return x * factor
return multiplier
double = create_multiplier_function(2)
triple = create_multiplier_function(3)
State Management Pattern
def create_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
def decrement():
nonlocal count
count -= 1
return count
return {
'increment': increment,
'decrement': decrement
}
counter = create_counter()
Closure Patterns Comparison
Pattern |
Use Case |
Key Characteristic |
Decorator |
Function modification |
Wraps original function |
Factory |
Dynamic function creation |
Generates customized functions |
State Management |
Maintaining state |
Encapsulates mutable state |
Memoization Pattern
def memoize(func):
cache = {}
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
Closure Flow Visualization
graph TD
A[Outer Function] --> B[Create Closure]
B --> C[Capture Variables]
C --> D[Return Inner Function]
D --> E[Execute Inner Function]
Advanced Closure Techniques
Configuration Closure
def configure_database(host, port):
def connect():
## Simulated database connection
print(f"Connecting to {host}:{port}")
return connect
mysql_connection = configure_database('localhost', 3306)
mysql_connection()
Common Use Cases
- Implementing decorators
- Creating function factories
- Managing stateful computations
- Implementing callback mechanisms
- Partial function application
- Closures have minimal performance overhead
- Useful for creating flexible, reusable code
- Avoid excessive memory retention
LabEx recommends mastering these patterns to write more elegant and efficient Python code.