Functions Returning Functions
Understanding Functions Returning Functions
In Python, functions can return other functions, which is a powerful feature of functional programming.
Basic Example
python
def outer():
def inner():
print("Welcome!")
return inner # Return the inner function (without calling it)
# Calling outer() returns the inner function
f = outer() # f now refers to the inner function
print(f"Type of f: {type(f)}") # <class 'function'>
print(f"Name of f: {f.__name__}") # inner
# Now we can call the inner function using f
f() # Output: Welcome!
More Practical Examples
Example 1: Function Factory
python
def create_greeter(greeting):
"""Returns a greeting function with a specific greeting"""
def greeter(name):
return f"{greeting}, {name}!"
return greeter
# Create different greeter functions
hello_greeter = create_greeter("Hello")
goodbye_greeter = create_greeter("Goodbye")
hey_greeter = create_greeter("Hey there")
# Use the created functions
print(hello_greeter("Alice")) # Output: Hello, Alice!
print(goodbye_greeter("Bob")) # Output: Goodbye, Bob!
print(hey_greeter("Charlie")) # Output: Hey there, Charlie!
Example 2: Math Operation Generator
python
def operation_factory(operator):
"""Returns a math operation function based on the operator"""
def calculate(a, b):
if operator == '+':
return a + b
elif operator == '-':
return a - b
elif operator == '*':
return a * b
elif operator == '/':
return a / b if b != 0 else "Cannot divide by zero"
else:
return "Invalid operator"
return calculate
# Create specific operation functions
add = operation_factory('+')
subtract = operation_factory('-')
multiply = operation_factory('*')
divide = operation_factory('/')
# Use the created functions
print(f"5 + 3 = {add(5, 3)}") # Output: 5 + 3 = 8
print(f"10 - 4 = {subtract(10, 4)}") # Output: 10 - 4 = 6
print(f"6 * 7 = {multiply(6, 7)}") # Output: 6 * 7 = 42
print(f"15 / 3 = {divide(15, 3)}") # Output: 15 / 3 = 5.0
Example 3: Counter with Closure
python
def create_counter():
"""Creates a counter function that remembers its state"""
count = 0
def counter():
nonlocal count # Allows modifying the outer variable
count += 1
return count
return counter
# Create counter instances
counter1 = create_counter()
counter2 = create_counter()
# Each counter maintains its own state
print(counter1()) # Output: 1
print(counter1()) # Output: 2
print(counter1()) # Output: 3
print(counter2()) # Output: 1 (independent counter)
print(counter2()) # Output: 2
Example 4: Decorator-like Pattern
python
def make_logger(func_name):
"""Creates a logging function for a specific purpose"""
def logger(message):
return f"[{func_name}] {message}"
return logger
# Create different loggers
error_logger = make_logger("ERROR")
warning_logger = make_logger("WARNING")
info_logger = make_logger("INFO")
# Use the loggers
print(error_logger("File not found")) # Output: [ERROR] File not found
print(warning_logger("Low memory")) # Output: [WARNING] Low memory
print(info_logger("Process completed")) # Output: [INFO] Process completed
Key Concepts Explained
- Higher-Order Functions: Functions that either take functions as parameters or return functions
create_greeter(),operation_factory(), andcreate_counter()are all higher-order functions
- Closures: Inner functions that remember variables from their enclosing scope
- In
create_counter(), the inner function remembers thecountvariable
- In
- Function Factories: Functions that create and return other functions
- Useful for creating specialized functions with preset configurations
- State Preservation: Returned functions can maintain state between calls
- Each counter instance maintains its own count
Why Return Functions?
- Code Reusability: Create specialized functions dynamically
- Encapsulation: Hide implementation details while exposing functionality
- State Management: Functions can maintain state without global variables
- Flexibility: Create custom behavior at runtime
Important Notes
- When returning a function, don’t use parentheses (e.g.,
return inner, notreturn inner()) - Use
nonlocalkeyword if you need to modify variables from the outer scope - Each returned function instance maintains its own closure environment