# 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.