medium +20 pts

Profile time decorator

Build a decorator that records call counts and total elapsed time for functions.

Write a decorator `profile_time` that wraps a function and records statistics about its calls. The decorator must return a wrapper function that: 1) increments the call count, 2) measures the wall-clock time of each call (in seconds, as a float) using `time.perf_counter()`, 3) accumulates the total elapsed time across all calls, and 4) exposes the statistics as attributes on the wrapper function: `.calls` (int) and `.total_time` (float). The wrapper must return the original function's return value. The decorated function should also preserve the original function's `__name__` and `__doc__` (you may use `functools.wraps`). Implement the decorator in Python. You must define the exact signature: `def profile_time(func):`. The decorator is applied with `@profile_time` above a function definition.

Constraints

- `profile_time` must work for any function that takes any number of positional and keyword arguments. - The wrapper must return the original function's return value unchanged. - `calls` and `total_time` must be accessible as attributes of the decorated function. - `calls` must be an integer, `total_time` must be a float. - Use `time.perf_counter()` for timing. - The decorator must preserve `__name__` and `__doc__` (e.g., via `functools.wraps`). - No external libraries.

Example

```python
@profile_time
def add(a, b):
    """Add two numbers."""
    return a + b

add(2, 3)      # returns 5
add(5, 6)      # returns 11
add.calls      # 2
add.total_time # some positive float, e.g., 1.2e-6

@profile_time
def slow_sum(n):
    import time
    time.sleep(0.1)
    return sum(range(n))

slow_sum(100)  # returns 4950
slow_sum(200)  # returns 19900
slow_sum.calls # 2
slow_sum.total_time # >= 0.2
```
20 points ~20 min

Recent Submissions

No submissions yet — hit Run Tests to try!

Hints

Use a mutable object (like a list or a dictionary) to store call count and total time because integers/floats are immutable and reassignment in the outer scope requires `nonlocal`.
Use `functools.wraps(func)` to copy metadata to the wrapper.
Call `time.perf_counter()` before and after invoking the original function, then accumulate the difference.
In the wrapper, set attributes like `wrapper.calls = count` and `wrapper.total_time = total` after each call (or use a nonlocal variable and update attributes).
Remember to return the original function's result.
Python 3
All tests passed!
Test Results
Press Ctrl+Enter or click Run Tests to execute your code.