Hone logo
Hone
Problems

Decorator Delight: Timing and Logging Functions

Decorators are a powerful feature in Python that allow you to modify or enhance the behavior of functions or methods without actually changing their code. This challenge will guide you through implementing decorators to both time the execution of functions and log their calls with arguments and return values. Understanding decorators is crucial for writing clean, reusable, and maintainable code.

Problem Description

You are tasked with creating two decorators: timer and logger.

  • timer Decorator: This decorator should measure and print the execution time of a function. It should take no arguments. The output should be a formatted string indicating the function name and its execution time in seconds, rounded to four decimal places.

  • logger Decorator: This decorator should log the function call, including the function name, arguments, and the return value. The log message should be a formatted string: "Function '{function_name}' called with arguments: {args}, returned: {return_value}". It should also take no arguments.

You need to implement both decorators and apply them to example functions to demonstrate their functionality.

Examples

Example 1:

def add(x, y):
  return x + y

@timer
@logger
def my_add(x, y):
  return add(x, y)

my_add(5, 3)

Output:

Function 'my_add' called with arguments: (5, 3), returned: 8
Execution time: 0.0000 seconds

Example 2:

def multiply(x, y):
  return x * y

@timer
def my_multiply(x, y):
  return multiply(x, y)

my_multiply(4, 6)

Output:

Function 'my_multiply' called with arguments: (4, 6), returned: 24
Execution time: 0.0000 seconds

Example 3: (Edge Case - Function with no arguments)

def greet():
  return "Hello!"

@timer
@logger
def my_greet():
  return greet()

my_greet()

Output:

Function 'my_greet' called with arguments: (), returned: Hello!
Execution time: 0.0000 seconds

Constraints

  • The timer decorator should use the time module to measure execution time.
  • The logger decorator should use the inspect module to retrieve function arguments.
  • The execution time should be rounded to four decimal places.
  • The decorators should work correctly with functions that have or do not have arguments.
  • The decorators should be able to be chained (as shown in Example 1).

Notes

  • Remember that decorators are essentially functions that take another function as an argument and return a modified version of that function.
  • The inspect module is helpful for introspecting functions and accessing their arguments. inspect.signature and inspect.getfullargspec are useful functions within the inspect module.
  • Consider using closures to preserve the original function's identity and arguments within the decorator.
  • Think about how to handle the return value of the decorated function within the logger decorator.
  • The order of decorators matters when chaining them. The innermost decorator is executed first.
Loading editor...
python