medium +20 pts

Memoize with TTL

Build a decorator that caches results for a limited time and then recomputes.

Write a decorator factory `memoize_ttl(ttl_seconds)` that caches the return value of a function for a fixed number of seconds. When the decorated function is called with the same arguments within the TTL window, the cached result is returned without calling the original function. When the TTL has expired, the original function is called again and the cache is refreshed. Requirements: - `memoize_ttl` must be a decorator factory: it takes a positive number `ttl_seconds` and returns a decorator function. - The returned decorator should wrap the original function and return a wrapper function. - Use positional and keyword arguments to build a cache key. The key must be hashable. - The cache must be per-function (each decorated function gets its own cache). - The decorator must work for functions with any number of positional/keyword arguments. - On each call, check the cache; if an entry exists and `time.time() - entry_time < ttl_seconds`, return the cached value. Otherwise, call the function, store the result with the current timestamp, and return it. - The cache should be stored in a dictionary attribute named `_cache` on the wrapper function. Each entry maps the key to a tuple `(timestamp, result)`. - The TTL value is fixed at decoration time. `ttl_seconds` is a positive number (int or float). - The wrapper function must be named `wrapper` and preserve the original function's `__name__` and `__doc__` using `functools.wraps`. You may import `time` and `functools`. Implement the function `memoize_ttl` that returns the decorator. Do not use external libraries.

Constraints

- `ttl_seconds` is a positive number (int or float). - Function arguments can be any hashable values (including tuples, strings, numbers). - The cache size is unbounded. - The solution must be deterministic; use `time.time()` as the clock. - Your code should handle functions that return `None`.

Example

>>> import time
>>> @memoize_ttl(2)
... def add(a, b):
...     print('computing...')
...     return a + b
>>> add(1, 2)
computing...
3
>>> add(1, 2)
3
>>> time.sleep(2.1)
>>> add(1, 2)
computing...
3
20 points ~20 min

Recent Submissions

No submissions yet — hit Run Tests to try!

Hints

Use a dictionary `_cache` on the wrapper to store `key -> (timestamp, value)`.
Build a key using a tuple of positional args and keyword args sorted by keyword.
Use `functools.wraps` to preserve the original function's metadata.
Check expiry by comparing `time.time() - timestamp < ttl_seconds`.
Python 3
All tests passed!
Test Results
Press Ctrl+Enter or click Run Tests to execute your code.