nextRound
TechnologiesCoding ProblemsBookmarksLearning PathsLogin
nextRound
TechnologiesCoding ProblemsBookmarksLearning PathsLogin
nextRound

AI-powered interview preparation platform. Practice with curated questions, mock interviews, and personalized learning paths to crack your dream tech interview.

Quick Links

  • Technologies
  • Mock Interviews
  • Saved Questions
  • Pricing

Company

  • About Us
  • Contact Us

Legal

  • Privacy Policy
  • Terms of Use

© 2026 nextRound. All rights reserved.

Questions
12 of 18
1Why is using a mutable default argument (e.g., `def f(x=[])`) considered a common pitfall?
2What is the purpose of the `nonlocal` keyword, and how does it differ from `global`?
3How does Python's `for` loop differ conceptually from a C-style `for` loop?
4How does structural pattern matching (`match`/`case`, introduced in Python 3.10) differ from a chain of `if`/`elif` statements?
5What are first-class functions, and how does Python's treatment of functions as objects enable higher-order functions?
6What is the purpose of the `else` clause on `for` and `while` loops, and when does it execute?
7How would you implement memoization for a recursive function, and what tradeoffs exist between manual caching and `functools.lru_cache`?
8What is the difference between positional, keyword, default, `*args`, and `**kwargs` parameters?
9Explain Python's LEGB rule for variable scope resolution.
10How does Python's `for` loop differ conceptually from a C-style `for` loop?
11What are first-class functions, and how does Python's treatment of functions as objects enable higher-order functions?
12How would you implement memoization for a recursive function, and what tradeoffs exist between manual caching and `functools.lru_cache`?
13What is the purpose of the `nonlocal` keyword, and how does it differ from `global`?
14What is the difference between positional, keyword, default, `*args`, and `**kwargs` parameters?
15Why is using a mutable default argument (e.g., `def f(x=[])`) considered a common pitfall?
16How does structural pattern matching (`match`/`case`, introduced in Python 3.10) differ from a chain of `if`/`elif` statements?
17What is the purpose of the `else` clause on `for` and `while` loops, and when does it execute?
18Explain Python's LEGB rule for variable scope resolution.
PythonPython
Basics
Control Flow and Functions
Data Structures
Comprehensions & Functional Programming
Iterators, Generators & Decorators
Object-Oriented Programming
Exception Handling & Debugging
Concurrency & Parallelism
Performance & Optimization
Testing
Security
Modules, Packaging & Environment
Type Hinting & Modern Python
System Design & Architecture with Python
Best Practices & Design Patterns
Edge Cases & Tricky Interview Questions
12 / 18

How would you implement memoization for a recursive function, and what tradeoffs exist between manual caching and `functools.lru_cache`?

Difficulty: 8/10
Functions & Scope, Memoization and Caching, functools.lru_cache

Memoizing recursion: manual dict cache vs functools.lru_cache

Memoization stores the result of a pure function keyed by its arguments so repeated calls skip the work. For a recursive function with overlapping subproblems, like Fibonacci or grid DP, it turns exponential time into linear time (each distinct argument is computed once) at the cost of O(n) memory. The manual version is a decorator holding a dict; the standard-library version is functools.lru_cache (bounded, LRU eviction) or functools.cache (3.9+, unbounded, simpler and slightly faster).

javascript

Manual vs lru_cache trade-offs. lru_cache is implemented in C, thread-safe for its own bookkeeping, supports maxsize and typed=True, offers cache_info() and cache_clear(), and handles keyword arguments, so I use it by default. A manual cache is worthwhile when you need custom behavior: TTL expiry, custom keys for unhashable arguments, per-instance caches, metrics, or cache invalidation. Both require hashable arguments and a pure, deterministic function; caching functions with side effects or time-dependent results is a bug.

Pitfalls I check in review: (1) unbounded caches (maxsize=None or functools.cache) grow forever in a long-running service, so bound them or clear them; (2) @lru_cache on an instance method includes self in the key, which keeps every instance alive and leaks memory, so use a per-instance cache, functools.cached_property for no-argument values, or cache a module-level function; (3) returned mutable objects are shared, so a caller who mutates the cached list corrupts later results - return tuples or copies; (4) f(1, 2) and f(a=1, b=2) are cached under different keys; (5) concurrent calls may compute the same value more than once, since the lock protects the cache but not the function call, so it is not a stampede protection.

Recursion limits matter: memoized top-down recursion still uses stack depth equal to the dependency chain, so the default limit (about 1000 frames) fails for deep inputs. Options are bottom-up dynamic programming with a loop (best), an explicit stack, or raising sys.setrecursionlimit cautiously; the last risks a hard crash on deep stacks. For distributed or multi-process services, in-process caches are per-process and cannot be invalidated centrally, so use an external cache such as Redis or a TTL cache library. Version note: functools.cache needs 3.9+, and lru_cache without parentheses (@lru_cache) works from 3.8.

Scenario Questions

0-2 years experience

  1. 1Why is a naive recursive fibonacci(35) so slow, and how does caching change the number of calls?
  2. 2What does adding @lru_cache above a function do, and what kind of arguments can't be used with it?

2-5 years experience

  1. 1Write a memoizing decorator using a dict. How would you handle keyword arguments and unhashable arguments?
  2. 2A long-running service uses lru_cache(maxsize=None) and its memory keeps growing. What is happening and how would you choose maxsize?

5-8 years experience

  1. 1You decorated an instance method with lru_cache and objects are never garbage collected. Why does that happen and what are the fixes?
  2. 2A cached function returns a list, callers mutate it, and later calls return corrupted data. Explain and give options.

8+ years experience

  1. 1A memoized recursive function raises RecursionError for n=10000. Compare bottom-up dynamic programming, an explicit stack and raising the recursion limit.
  2. 2Design a caching layer for an expensive function in a multi-process web service with TTL requirements. Why isn't lru_cache enough, and how would you handle invalidation and cache stampedes?

Follow-up Questions

  • Why does decorating an instance method with lru_cache cause a memory leak?
  • What are the differences between functools.cache, lru_cache and cached_property?
Sharethis question

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.