# Execution Timer Wrapper

> Function wrapped with a timer. Duration captured on exit.

Canonical URL: <https://datadriven.io/problems/execution_timer_wrapper>

Domain: Python · Difficulty: medium · Seniority: L6

## Problem

Implement make_timed(fn) that returns a wrapper which invokes fn with any positional and keyword args, measures elapsed seconds, and returns fn's return value unchanged (timing is not verified by tests). Also implement run_timed(fn, args=(), kwargs=None): given fn as a lambda source string, args list, and kwargs dict, eval the source into a callable, wrap it with make_timed, invoke it with the given args/kwargs, and return the result.

## Worked solution and explanation

### Why this problem exists in real interviews

This tests **closures**, **higher-order functions**, and **the decorator pattern**. It reveals whether you understand how `*args, **kwargs` forwarding works and how to measure elapsed time around a function call.

---

### Break down the requirements

#### Step 1: Define an inner wrapper function

The wrapper captures the original function via closure and forwards all arguments.

#### Step 2: Measure elapsed time using time.time()

Record the start time before calling the function and compute the difference after it returns.

#### Step 3: Return both the result and the elapsed time

The wrapper returns a tuple of the original result and the rounded elapsed time.

---

### The solution

**Closure-based timing wrapper with argument forwarding**

```python
import time
def make_timed(fn):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = fn(*args, **kwargs)
        elapsed = round(time.time() - start, 4)
        return result, elapsed
    return wrapper
```

> **Time and Space Complexity**
>
> **Time:** O(1) overhead for the wrapper itself. The total time depends on the wrapped function.
> 
> **Space:** O(1) for the closure. No additional data structures.

> **Interviewers Watch For**
>
> Correct use of `*args, **kwargs` to forward all argument types. Also, using `time.time()` rather than `time.clock()` (deprecated) or `time.perf_counter()` (better precision but less commonly expected in interviews).

> **Common Pitfall**
>
> Forgetting to return the wrapper function from `make_timed`. Without the `return wrapper` line, `make_timed` returns `None`.

---

## Common follow-up questions

- How would you use functools.wraps to preserve the original function metadata? _(Tests knowledge of `@functools.wraps(fn)` to copy `__name__`, `__doc__`, etc.)_
- What if the wrapped function raises an exception? _(Tests try/finally to still measure elapsed time even when the function fails.)_
- How would you make this a decorator with configurable precision? _(Tests nested closures: a factory that takes precision and returns the decorator.)_
- What is the difference between time.time() and time.perf_counter()? _(Tests knowledge of clock sources: perf_counter has higher resolution and is not affected by system clock adjustments.)_

## Related

- [All practice problems](https://datadriven.io/problems)
- [Mock interview mode](https://datadriven.io/interview/execution_timer_wrapper)
- [Python Interview Questions](https://datadriven.io/python-interview-questions)
- [Data Engineering Interview Prep Guide](https://datadriven.io/data-engineer-interview-prep)
- [Daily Challenge](https://datadriven.io/daily)

---

Source: DataDriven (https://datadriven.io). 100% free data engineering interview prep. Live code execution against Postgres 16, Python 3.11, and Spark sandboxes. No paywall, no premium tier, no signup gate.