Build a Python decorator that times any function, prints how long it took and preserves its name with functools.wraps. Tested against a real call.
The problem
Write a decorator timed that:
- calls the wrapped function with any arguments and returns its result
- prints exactly
Function <name> took <seconds> seconds, with seconds formatted to 4 decimal places (e.g.Function calculate took 0.0023 seconds) - keeps the original function's
__name__(usefunctools.wraps)
The test decorates its own calculate(a, b=1) function and checks all three.
Examples
Example 1
Input
check_timed(timed)
Expected output
(42, 'calculate', True)
+ 1 hidden test on Submit — returns the wrapped result.
Edge cases to ask about
- Functions with keyword arguments
- Return value must pass through
- Exceptions (use try/finally to still print)
How the tests call your code
These helpers run before your code. The test inputs above call them.
import re as _re def check_timed(timed): @timed def calculate(a, b=1): return a * b printed = captured(calculate, 6, b=7) result = calculate(6, b=7) pattern = r"^Function calculate took \d+\.\d{4} seconds$" return (result, calculate.__name__, bool(_re.match(pattern, printed.strip())))
Hints
0/3How an interviewer scores this
0/9Your code runs in real CPython inside your browser — nothing is sent anywhere. The first run downloads the interpreter (about 6 MB, once). Your code is saved on this device as you type.
Complexity Lab
What does this cost as n grows?
Interviewers score the analysis as much as the code. Commit to an answer first — then check it, and read why.
Pick both to reveal the answer.
From brute force to optimal
The progression an interviewer wants to hear, one step at a time.
| Approach | Time | Space | Idea |
|---|---|---|---|
| Closure + functools.wraps | O(1) overhead | O(1) | perf_counter is the right clock for intervals. |
Walkthrough of the optimal approach (try it yourself first)
timed(func) returns wrapper, which records time.perf_counter() before and after calling func(*args, **kwargs), prints the elapsed time and returns the result (forgetting the return is the most common bug).
Without @functools.wraps(func) the decorated function's __name__ becomes "wrapper", breaking logging, debugging and anything that introspects it.
Use perf_counter, not time.time — it is monotonic and high-resolution.
Complexity: O(1) time, O(1) space. The decorator adds a constant amount of work around each call.
Reveal the reference solution
import time import functools def timed(func): @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) elapsed = time.perf_counter() - start print(f"Function {func.__name__} took {elapsed:.4f} seconds") return result return wrapper
Follow-ups interviewers ask
- Still print the time when the function raises.
- Make it work on async functions.
Frequently asked interview questions
Core interview concepts, complexities, and follow-ups scored by hiring teams.
What is the time complexity of Write a Timing Decorator in Python?
The optimal solution runs in O(1) time and O(1) auxiliary space. The decorator adds a constant amount of work around each call.
What follow-up questions do interviewers ask about Write a Timing Decorator?
Still print the time when the function raises. Make it work on async functions.
