Higher-Order Functions and Decorators

Higher-Order Functions and Decorators

Higher-order functions are functions that can take other functions as arguments or return them as results. Decorators are a form of higher-order function that allow you to add behavior to existing functions.

Here’s a complete example that demonstrates the use of higher-order functions, decorators, and their application on recursive functions:

import time

# Decorator to measure execution time
def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function '{func.__name__}' executed in {end_time - start_time:.6f} seconds")
        return result
    return wrapper

# Decorator to log function calls
def logging_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling function '{func.__name__}' with arguments {args} and {kwargs}")
        result = func(*args, **kwargs)
        print(f"Function '{func.__name__}' returned {result}")
        return result
    return wrapper

# Applying multiple decorators
@timing_decorator
@logging_decorator
def factorial(n):
    """Recursively calculate the factorial of n."""
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

@timing_decorator
@logging_decorator
def fibonacci(n):
    """Recursively calculate the nth Fibonacci number."""
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

# Test the decorated functions
print(f"Factorial of 5: {factorial(5)}")
print(f"Fibonacci of 10: {fibonacci(10)}")

Code Explanation

  1. timing_decorator:
    • This decorator measures the execution time of a function.
    • It records the start time before the function call and the end time after the function call.
    • It prints the time taken for the function to execute.
  2. logging_decorator:
    • This decorator logs the function calls and their results.
    • It prints the function name, the arguments it was called with, and the result it returned.
  3. Applying Multiple Decorators:
    • The factorial and fibonacci functions are decorated with both timing_decorator and logging_decorator.
    • The decorators are applied in a specific order: the logging_decorator wraps the function first, followed by the timing_decorator.
  4. factorial Function:
    • This function calculates the factorial of a number n recursively.
    • If n is 0, it returns 1 (base case).
    • Otherwise, it returns n multiplied by the factorial of n-1.
  5. fibonacci Function:
    • This function calculates the nth Fibonacci number recursively.
    • If n is less than or equal to 0, it returns 0 (base case for non-positive integers).
    • If n is 1, it returns 1 (base case).
    • Otherwise, it returns the sum of the Fibonacci numbers of n-1 and n-2.
  6. Testing the Functions:
    • The factorial function is tested with the input 5.
    • The fibonacci function is tested with the input 10.

Output Example

When you run the above code, you will get output similar to the following:

Calling function 'factorial' with arguments (5,) and {}
Calling function 'factorial' with arguments (4,) and {}
Calling function 'factorial' with arguments (3,) and {}
Calling function 'factorial' with arguments (2,) and {}
Calling function 'factorial' with arguments (1,) and {}
Calling function 'factorial' with arguments (0,) and {}
Function 'factorial' returned 1
Function 'factorial' returned 1
Function 'factorial' returned 2
Function 'factorial' returned 6
Function 'factorial' returned 24
Function 'factorial' returned 120
Function 'factorial' executed in 0.000021 seconds
Factorial of 5: 120
Calling function 'fibonacci' with arguments (10,) and {}
Calling function 'fibonacci' with arguments (9,) and {}
...
Function 'fibonacci' executed in 0.005631 seconds
Fibonacci of 10: 55

This output shows the logging and timing information for each call to the factorial and fibonacci functions, demonstrating the combined effects of the decorators.