easy +10 pts

Context Decorator Dual

Build @timed to log execution time in seconds and context manager Timing to measure block durations.

Implement two tools for measuring execution time. 1. Define a decorator `timed(func)` that wraps `func`. The wrapper should call the original function, measure elapsed wall-clock time in seconds using `time.perf_counter()`, and append the elapsed time (as a float) to a global list `TIMES` after the call returns (or raises). The wrapper must return the original function's return value (if any). Use `TIMES` as a module-level list. 2. Define a context manager class `Timing` that, upon entering, records the start time using `time.perf_counter()`. When exiting normally or via exception, it appends the elapsed time in seconds to the same global `TIMES` list. The `__enter__` method should return the `Timing` instance (or anything). If an exception occurs, it must NOT suppress it. In both cases, the appended value should be a float representing seconds elapsed. Implement the following: - `TIMES` as a module-level list. - `timed(func)` decorator. - `Timing` class with `__enter__` and `__exit__`. Additionally, implement the following helper functions that are used by the tests: - `call_timed_and_check_times()`: Clears `TIMES`, applies `timed` to a function that returns 5 (e.g., `def f(): return 5`), calls it, and returns a list `[return_value, len(TIMES)]`. - `call_timing_and_check_times()`: Clears `TIMES`, enters `Timing()` with an empty block, and returns `[len(TIMES)]`. - `call_timed_with_exception()`: Clears `TIMES`, applies `timed` to a function that raises a `ValueError` (e.g., `def f(): raise ValueError('boom')`), calls it, catches the exception, clears `TIMES`? No: returns the string `'exception'` (the decorator must not suppress the exception; the helper should catch it and return the string `'exception'`). - `call_timing_with_exception()`: Clears `TIMES`, enters `Timing()` with a block that raises a `ValueError`, catches the exception, and returns the string `'exception'` (the context manager must propagate it).

Constraints

- The input functions and blocks are deterministic in behavior (no I/O). - Use `time.perf_counter()` for precise timing. - The decorator must work on functions with any arguments and keyword arguments. - The context manager must handle exceptions without suppressing them. - Assume `TIMES` may be cleared before each test; your implementation must append to it.

Example

```python
>>> TIMES.clear()
>>> @timed
... def add(a, b):
...     return a + b
>>> add(2, 3)
5
>>> len(TIMES) == 1
True
>>> TIMES[0] >= 0
True

>>> TIMES.clear()
>>> with Timing() as t:
...     pass
>>> len(TIMES) == 1
True
>>> TIMES[0] >= 0
True
```
10 points ~15 min

Recent Submissions

No submissions yet — hit Run Tests to try!

Hints

In the decorator, measure time before and after calling the function, then append the difference in a finally block.
In `__enter__`, record `self.start = time.perf_counter()`. In `__exit__`, append `time.perf_counter() - self.start` and return `False`.
The helper functions should clear `TIMES` at the start and then exercise the decorator/context manager.
For exception helpers, catch the `ValueError` and return the string `'exception'`.
Python 3
All tests passed!
Test Results
Press Ctrl+Enter or click Run Tests to execute your code.