Debug Python LRU Cache-Key Construction
Company: Anthropic
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: hard
Interview Round: Onsite
# Debug Python LRU Cache-Key Construction
The source reports a Python LRU-cache bug in key construction from `args` and `**kwargs` but does not provide the exact implementation. The decorator below is a practice reconstruction of that reported failure mode.
```python
from collections import OrderedDict
from functools import wraps
def memoize_lru(maxsize=128):
def decorate(function):
cache = OrderedDict()
@wraps(function)
def wrapped(*args, **kwargs):
key = args + tuple(kwargs.items())
if key in cache:
cache.move_to_end(key)
return cache[key]
value = function(*args, **kwargs)
cache[key] = value
if len(cache) > maxsize:
cache.popitem(last=False)
return value
return wrapped
return decorate
```
Find the cache-key bugs and repair the decorator for ordinary Python signatures under this practice contract:
- Calls that bind the same values to the same parameters, including defaults, share an entry regardless of positional versus keyword spelling or keyword insertion order.
- The supported value domain is `None`, booleans, integers, floats, strings, bytes, and recursively nested tuples or frozensets of supported values. Other argument values raise `TypeError` before the wrapped function runs.
- Type is part of the frozen representation, so `True` and `1` do not collide.
- `*args` and `**kwargs` are supported. Keyword names are strings and are canonicalized in name order.
- Exceptions from the wrapped function are not cached. `maxsize` is a positive integer.
### Clarifying Questions to Ask
- Should positional and keyword spellings of the same bound call share an entry?
- Which mutable or custom values, if any, are safe to cache?
- Should argument types be distinguished when values compare equal?
- Are exceptions cached, and is thread safety required?
### What a Strong Answer Covers
- Minimal failures for keyword order, signature binding, defaults, and unhashable values.
- Canonical binding with `inspect.signature`, including variadic parameters.
- A collision-resistant frozen representation and explicit unsupported-value policy.
- Correct LRU recency updates, eviction, exception behavior, and complexity.
- The difference between map/recency locking and per-key duplicate-work suppression.
### Follow-up Questions
1. How would you add thread safety without holding a global lock during user code?
2. When is content-freezing a mutable argument semantically unsafe?
3. How would code or data version changes invalidate old entries?
Quick Answer: Debug a Python LRU memoization decorator whose cache keys depend incorrectly on argument spelling and keyword order. Build canonical signature-bound keys, freeze only supported nested values with type distinctions, preserve exception behavior, and explain safe thread synchronization.