100+ Python Interview Questions and Answers for 2026
Master Python Interview Questions for 2026
Python is the most-used language at every major tech company for backend services, data infrastructure, ML pipelines, and tooling. Whether you're interviewing for a backend role at Stripe, a data engineer position at Netflix, or a machine learning engineer slot at Meta, expect Python-specific questions alongside the algorithmic round.
This guide covers 100+ Python interview questions across eight categories: language fundamentals, data structures, OOP, functional programming, concurrency, memory and performance, testing, and Python-specific algorithm patterns. Each section progresses from junior-level to senior-level questions.
Quick Navigation
- Python Fundamentals (Q1–Q18)
- Data Structures and Built-ins (Q19–Q35)
- Object-Oriented Python (Q36–Q52)
- Functional and Iterator Patterns (Q53–Q66)
- Concurrency: Threads, asyncio, Multiprocessing (Q67–Q80)
- Memory, Performance, and the GIL (Q81–Q92)
- Testing and Debugging (Q93–Q100)
- Python Coding Problems (Q101–Q110)
Section 1: Python Fundamentals
Q1. What are the key differences between Python 2 and Python 3?
Python 2 reached end-of-life in January 2020. Python 3 introduced print as a function, made strings Unicode by default, replaced integer division (/) with true division, added type hints, async/await, f-strings, the walrus operator, structural pattern matching (3.10), and unified type/exception hierarchies. Any new code should be Python 3.10+.
Q2. What is PEP 8 and why does it matter in interviews?
PEP 8 is the official Python style guide: 4-space indentation, snake_case for functions/variables, PascalCase for classes, UPPER_SNAKE for constants, two blank lines between top-level definitions, max 79 characters per line. Interviewers care about it because it signals you've written code that other people had to read.
Q3. Mutable vs. immutable types — give examples.
Immutable: int, float, bool, str, tuple, frozenset, bytes. Mutable: list, dict, set, bytearray. The distinction matters because immutable objects can be hash keys, are safe to share across threads, and are passed by reference but cannot be modified in place.
Q4. Why is the default argument mutable bug so dangerous?
Default arguments are evaluated once, at function-definition time:
def append_item(item, items=[]):
items.append(item)
return items
# append_item(1) → [1]
# append_item(2) → [1, 2] # surprise: shared state
Fix: def append_item(item, items=None): items = items or []
Q5. What does is vs == actually compare?
== compares values via __eq__. is compares object identity (memory address). a is None is the idiomatic null check because None is a singleton. Never use is for string or integer comparison — CPython interns small integers and short strings, but the behavior is implementation-defined.
Q6. Explain truthiness in Python.
Falsy values: None, False, 0, 0.0, empty sequences ("", [], (), {}), and any object whose __bool__ returns False or __len__ returns 0. Everything else is truthy. This is why if items: is preferred over if len(items) > 0:.
Q7. How does Python handle integer overflow?
It doesn't. Python integers are arbitrary precision — they grow to fit the value, limited only by memory. This is different from C/Java where ints are fixed-width and overflow silently.
Q8. What's the difference between /, //, and %?
/ is true division (always returns float). // is floor division (returns int if both operands are int). % is modulo. 7 // 2 → 3, 7 / 2 → 3.5, 7 % 2 → 1. Note: floor division of negatives floors toward negative infinity: -7 // 2 → -4.
Q9. What does *args and **kwargs do?
*args collects positional arguments into a tuple; **kwargs collects keyword arguments into a dict. They're a convention — the names args and kwargs aren't special, but using anything else will confuse readers.
Q10. Explain unpacking with examples.
a, b, c = [1, 2, 3]
first, *rest = [1, 2, 3, 4] # first=1, rest=[2, 3, 4]
*init, last = [1, 2, 3, 4] # init=[1, 2, 3], last=4
a, b = b, a # swap, no temp needed
Q11. What is a docstring and how is it different from a comment?
A docstring is a string literal as the first statement in a module, function, class, or method body. It's accessible at runtime via __doc__ and powers help(). Comments (#) are stripped at compile time and invisible at runtime.
Q12. What is the GIL and what does it actually do?
The Global Interpreter Lock is a mutex in CPython that allows only one thread to execute Python bytecode at a time. It exists because CPython's memory management isn't thread-safe. Consequence: pure-Python CPU-bound work doesn't benefit from threads — use multiprocessing or move hot loops to C extensions (NumPy, Cython). I/O-bound work still benefits from threads because the GIL is released during I/O syscalls. Python 3.13 (2024) shipped an experimental no-GIL build.
Q13. What are type hints and are they enforced at runtime?
Type hints (PEP 484) annotate variables, parameters, and return types: def add(x: int, y: int) -> int:. They are not enforced at runtime — Python ignores them. Tools like mypy, pyright, and Pyre check them statically. They show up in IDE autocomplete and improve refactoring safety.
Q14. Difference between a module and a package?
A module is a single .py file. A package is a directory containing an __init__.py (or a namespace package, post-PEP 420). Packages can contain submodules. import os.path imports the path submodule of the os package.
Q15. What does if __name__ == "__main__": do?
It guards code that should only run when the file is executed directly, not when imported. __name__ is set to "__main__" when running as a script, or to the module name when imported.
Q16. What is virtual environment and why use one?
A venv is an isolated Python installation with its own site-packages. Prevents project A's dependencies from breaking project B. Standard tooling: python -m venv .venv, then source .venv/bin/activate. Modern alternatives: uv, Poetry, pipenv, Hatch.
Q17. What's the difference between shallow copy and deep copy?
Shallow copy (list.copy(), copy.copy()) duplicates the outer container but shares nested objects. Deep copy (copy.deepcopy()) recursively duplicates everything. Matters when you mutate nested structures.
Q18. What's the difference between str.format(), %-formatting, and f-strings?
%-formatting is the oldest ("Hello, %s" % name) and most error-prone. str.format() is more flexible. f-strings (3.6+) are the fastest and most readable for the common case: f"Hello, {name}". Use f-strings everywhere except when the format string comes from user input — then use .format() with placeholders.
Section 2: Data Structures and Built-ins
Q19. List vs. tuple — when do you use which?
List is mutable, tuple is immutable. Use a tuple for fixed-size heterogeneous records (like a (lat, lon) pair) and for return values that group multiple things. Use a list for ordered collections you'll modify. Tuples are also hashable, so they can be dict keys or set elements.
Q20. How is a Python dict implemented?
Hash table with open addressing. Since CPython 3.7, insertion order is preserved (officially, not just an implementation detail). Average O(1) lookup, insertion, deletion. Worst case O(n) on hash collisions.
Q21. What does collections.defaultdict solve?
Removes the boilerplate of checking if a key exists before appending/incrementing:
counts = defaultdict(int)
for word in text.split():
counts[word] += 1 # no KeyError
Q22. When would you use collections.Counter?
Frequency counting and multiset operations. Counter("abracadabra").most_common(2) returns the two most frequent characters. Supports addition, subtraction, and intersection between counters.
Q23. What is collections.deque and when is it better than a list?
Doubly-linked list with O(1) append and pop from both ends. Use it for queues and sliding windows. list.pop(0) is O(n) because it shifts every element.
Q24. Difference between set and frozenset?
Both are unordered hash-based collections. set is mutable, frozenset is immutable and hashable. Use frozenset when you need a set as a dict key or set element.
Q25. How does list slicing actually work?
lst[start:stop:step] returns a new list. lst[::-1] reverses. lst[::2] takes every other element. lst[:] is a shallow copy. Slicing never raises IndexError; out-of-range indices clip silently.
Q26. What does dict.get(key, default) vs dict[key] do differently?
dict[key] raises KeyError if missing. dict.get(key) returns None. dict.get(key, default) returns default. dict.setdefault(key, default) also sets it.
Q27. When do you use OrderedDict now that regular dicts preserve order?
Rarely. OrderedDict still has move_to_end() and equality comparison that considers order — useful for LRU cache implementations or when order-sensitive equality matters.
Q28. What's the difference between append, extend, and += on lists?
append(x) adds x as a single element. extend(iterable) adds each element. list += iterable is equivalent to extend. list = list + iterable creates a new list (slower).
Q29. How do you reverse a list?
In place: lst.reverse(). New list: lst[::-1] or list(reversed(lst)). reversed() returns an iterator, which is more memory-efficient if you only iterate.
Q30. How do you sort a list of dicts by a key?
users.sort(key=lambda u: u["age"])
# or:
from operator import itemgetter
users.sort(key=itemgetter("age")) # faster
# Stable sort: equal keys preserve insertion order
Q31. What does zip() do and what about zip_longest()?
zip(a, b) pairs elements until the shorter iterable ends. itertools.zip_longest(a, b, fillvalue=None) continues to the longer one, padding with fillvalue. Python 3.10+ added strict=True to zip() which raises if iterables have different lengths.
Q32. How do you flatten a list of lists?
nested = [[1, 2], [3, 4], [5]]
flat = [x for sub in nested for x in sub]
# or:
from itertools import chain
flat = list(chain.from_iterable(nested))
Q33. What is a set comprehension and a dict comprehension?
{x*x for x in range(5)} # set comprehension
{x: x*x for x in range(5)} # dict comprehension
Q34. What happens when you iterate over a dict?
You iterate over keys by default. Use dict.values() or dict.items() for values or (key, value) pairs. These return views — they reflect changes to the underlying dict in real time.
Q35. Time complexity of common dict and list operations?
dict: get/set/delete O(1) average. list: index access O(1), append O(1) amortized, insert/delete at arbitrary index O(n), x in list O(n), x in set O(1).
Section 3: Object-Oriented Python
Q36. Difference between __init__ and __new__?
__new__ creates the instance (returns it). __init__ initializes the already-created instance (returns None). You override __new__ for singleton patterns or immutable subclasses; __init__ for everything else.
Q37. What is self and why is it explicit?
self is the instance the method is called on. Python passes it explicitly so that Class.method(instance) and instance.method() are equivalent. PEP 20: "explicit is better than implicit."
Q38. Class method vs. static method vs. instance method?
@staticmethod: no implicit first argument. Just a function namespaced under the class.@classmethod: receivescls(the class) as first arg. Used for alternative constructors.- Instance method: receives
self.
Q39. What is method resolution order (MRO)?
The order Python searches base classes for an attribute. Python uses C3 linearization. Inspect with ClassName.__mro__. Diamond inheritance works predictably because of MRO.
Q40. What does super() actually call?
It calls the next class in the MRO, not necessarily the immediate parent. In multiple inheritance, super().__init__() walks the MRO chain — this is why all __init__s in a cooperative hierarchy should call super().__init__().
Q41. What are dunder methods?
"Double underscore" methods (also "magic methods") that Python calls to implement built-in behavior. Examples: __len__ for len(), __add__ for +, __iter__ for iteration, __repr__ for the interactive prompt, __eq__ for ==.
Q42. __repr__ vs __str__ — what's the difference?
__repr__ is for developers: should be unambiguous, ideally a string that, evaluated, recreates the object. __str__ is for users: readable. If you only define one, define __repr__ — it's the fallback for str().
Q43. What is a property and when do you use one?
A property lets you expose an attribute that's actually computed by a method. Use it when you start with a public attribute and later need validation or a derived value — you can convert without breaking callers:
class Circle:
def __init__(self, radius): self._radius = radius
@property
def area(self): return 3.14159 * self._radius ** 2
Q44. What is a dataclass?
@dataclass (Python 3.7+) auto-generates __init__, __repr__, __eq__, and optionally __hash__ and ordering methods from class-level field declarations. Saves boilerplate for data containers.
Q45. dataclass vs. NamedTuple vs. TypedDict vs. plain dict — when?
- NamedTuple: immutable, indexed and named access, tiny memory footprint.
- dataclass: mutable, type-hinted, can have methods. Default for most cases.
- TypedDict: typed dict (still a dict at runtime). Use for JSON-shaped data.
- plain dict: when keys are dynamic and unknown at code-write time.
Q46. Abstract base classes — what problem do they solve?
abc.ABC and @abstractmethod let you define an interface that subclasses must implement. The class can't be instantiated until all abstract methods are overridden. Useful for plugin systems and enforcing API contracts.
Q47. What is duck typing?
"If it walks like a duck and quacks like a duck, it's a duck." Python doesn't care about an object's type — only whether it has the methods you call on it. file.write() works on any object with a write() method.
Q48. What is __slots__ and why use it?
By default, instances store attributes in a per-instance __dict__. __slots__ = ("x", "y") tells Python to use a fixed-size array instead, saving memory and slightly speeding attribute access. Trade-off: no dynamic attributes, no __weakref__ unless declared.
Q49. What is a metaclass?
A metaclass is the class of a class. type is the default. You override it to control class creation — for ORMs, frameworks, or registering subclasses. Rarely needed; use class decorators or __init_subclass__ first.
Q50. What does __init_subclass__ do?
Called on the parent when a subclass is defined. Lighter-weight than a metaclass for the common "register subclasses" pattern.
Q51. Composition vs. inheritance — which does Python prefer?
Same as every other OO language: prefer composition. Inheritance creates tight coupling and is hard to refactor. Use inheritance only for true "is-a" relationships and for sharing implementation in clear hierarchies.
Q52. What does @functools.total_ordering do?
If you define __eq__ and one of __lt__, __le__, __gt__, or __ge__, the decorator fills in the rest. Saves boilerplate for ordered classes.
Section 4: Functional and Iterator Patterns
Q53. What is a generator and how is it different from a list comprehension?
A generator computes values lazily: (x*x for x in range(10**9)) produces values one at a time. A list comp materializes everything. Use generators for large or infinite sequences.
Q54. What does yield do?
Pauses function execution and returns a value to the caller. On the next call, execution resumes after the yield. The function is now a generator function — calling it returns a generator object.
Q55. What is yield from?
Delegates iteration to a sub-iterator. yield from inner() is equivalent to for x in inner(): yield x, but also forwards send(), throw(), and the return value.
Q56. Difference between map, filter, and a comprehension?
Functionally equivalent. Comprehensions are more readable and slightly faster in CPython. map and filter shine when you have an existing function to apply: map(int, strings) reads better than [int(s) for s in strings].
Q57. What is functools.reduce and why is it rare in Python?
reduce(f, iterable) applies f cumulatively. reduce(lambda a, b: a*b, [1, 2, 3, 4]) → 24. Guido moved it out of builtins because explicit loops or sum/min/max are usually clearer.
Q58. What is a lambda and when should you use one?
Anonymous single-expression function: lambda x: x + 1. Use only for trivial throwaway functions passed to sorted, map, filter, etc. For anything longer, define a named function.
Q59. What is a decorator?
A function that takes a function and returns a function. @decorator above a function definition is sugar for func = decorator(func). Used for cross-cutting concerns: logging, timing, caching, auth.
Q60. Why do decorators usually need functools.wraps?
Without it, the decorated function loses its original __name__, __doc__, and __wrapped__ attributes — breaking introspection and tooling.
Q61. What is functools.lru_cache and when does it help?
Memoization decorator. Caches function results keyed by arguments. Hugely helpful for pure functions with overlapping inputs (Fibonacci, recursive parsers).
Q62. What is a closure?
A nested function that captures variables from its enclosing scope. The captured variables outlive the outer function call.
Q63. Why does this loop print 3 three times?
callbacks = [lambda: i for i in range(3)]
for cb in callbacks: print(cb()) # 2, 2, 2
The lambdas capture i by reference, not by value. By the time you call them, i is 2. Fix: lambda i=i: i — default arguments are evaluated once at definition time, capturing the current value.
Q64. What is the itertools module's most useful function in interviews?
combinations, permutations, product, chain, groupby, accumulate, and islice. Knowing these turns several lines of nested loops into a one-liner.
Q65. What is partial and when is it useful?
functools.partial(f, x=1) creates a new callable with x pre-bound. Useful for callback APIs where you can't pass extra arguments.
Q66. Why isn't tail-call optimization in Python?
Deliberate design choice. Guido argued that proper stack traces matter more than tail-call performance. Convert deep recursion to iteration manually.
Section 5: Concurrency
Q67. Threads vs. processes vs. asyncio — when do you use each?
- Threads: I/O-bound work (HTTP, DB, file). GIL is released during blocking I/O.
- Multiprocessing: CPU-bound pure-Python work. Each process has its own GIL.
- asyncio: I/O-bound with thousands of concurrent connections. Single-threaded, cooperative scheduling.
Q68. What is asyncio in 30 seconds?
A library for single-threaded concurrency using async def and await. The event loop runs coroutines; await suspends until an awaitable resolves. Excellent for high-fan-out network code (web scrapers, web servers).
Q69. What does await actually do?
Yields control back to the event loop until the awaited coroutine completes. The current coroutine is paused, other ready coroutines run, then it resumes.
Q70. What is the difference between asyncio.gather and asyncio.wait?
gather returns results in the order tasks were passed, raises on first error (by default). wait returns sets of done/pending tasks, lets you handle errors per-task. Use gather for the common case; wait when you need finer control.
Q71. What's a TaskGroup?
Python 3.11+ context manager that supervises a group of tasks. Cancels remaining tasks if one fails. Replaces most uses of gather.
Q72. Why can't you call a blocking function inside an async function?
It blocks the event loop — every other coroutine pauses. Use loop.run_in_executor() or asyncio.to_thread() to run blocking code on a thread.
Q73. What is a race condition in Python?
Two threads modifying shared state without synchronization. Even counter += 1 isn't atomic — it's a load, add, store. Use threading.Lock or atomic operations.
Q74. multiprocessing.Pool vs. concurrent.futures.ProcessPoolExecutor?
ProcessPoolExecutor is the modern, simpler API and matches ThreadPoolExecutor. Pool has more knobs (chunksize, ordered/unordered map). For new code, start with the executor.
Q75. What is the difference between concurrency and parallelism?
Concurrency: handling many things at once (asyncio, threads). Parallelism: doing many things at once (multiprocessing, multiple cores). Python's GIL allows concurrent threads but not parallel pure-Python execution.
Q76. How do you share data between processes?
Each process has its own memory. Options: multiprocessing.Queue, Pipe, shared_memory, Manager. Pickling overhead means shared state is expensive — prefer functional decomposition.
Q77. What is a daemon thread?
A thread that doesn't block the program from exiting. The Python process terminates when all non-daemon threads finish. Useful for background workers you don't need to clean up.
Q78. What is queue.Queue and is it thread-safe?
Yes, fully thread-safe. The canonical producer-consumer primitive in stdlib threading code.
Q79. What is the GIL's effect on web frameworks?
Sync frameworks (Flask, Django classic) handle one request per worker thread. CPython is fine because requests are I/O-bound. Async frameworks (FastAPI, Sanic) handle thousands of concurrent connections per worker — better fit for high-fan-out APIs.
Q80. What changes with Python 3.13's no-GIL build?
True parallel multi-threaded Python execution. Currently opt-in and experimental. Most C extensions need updates before they're safe in no-GIL mode. Production adoption is still 1-2 years out.
Section 6: Memory, Performance, and the GIL
Q81. How does Python manage memory?
Reference counting (every object tracks how many references point to it) plus a cyclic garbage collector to break reference cycles. Objects are deallocated when their refcount drops to zero.
Q82. What is gc.collect() and when do you call it?
Forces a cyclic garbage collection. Rarely needed in application code. Useful in long-running processes after deleting large object graphs you suspect contain cycles.
Q83. Why are tuples faster than lists?
Smaller memory footprint and CPython caches small empty tuples. Both have O(1) indexing, so the speedup matters mainly for tight loops over millions of elements.
Q84. What is interning?
CPython caches small integers (-5 to 256) and certain strings so equal values share the same object. Saves memory; never rely on it for correctness.
Q85. How do you profile a slow Python function?
cProfilefor function-level timing.line_profilerfor per-line timing.memory_profilerfor per-line memory use.py-spyfor sampling profiling of running processes.
Q86. What is __slots__'s memory impact?
Removes the per-instance __dict__. On 64-bit systems, saves ~200+ bytes per instance. Significant when you have millions of instances.
Q87. What is the difference between x += 1 and x = x + 1?
For immutables (int, str, tuple) they're equivalent. For mutables (list), += calls __iadd__ (in-place), while x = x + y calls __add__ (new object).
Q88. How does string concatenation in a loop scale?
s += chunk in a loop is O(n²) because strings are immutable — each concatenation copies. Use "".join(chunks) for O(n).
Q89. When does NumPy actually help?
When you can express your computation as vectorized operations on arrays. NumPy operations drop into C, bypassing the interpreter and the GIL. Pure-Python loops over NumPy arrays are slower than over lists.
Q90. What is Cython / mypyc?
Tools that compile Python (or annotated Python) to C extensions. Cython is more mature and lets you mix Python and C types. mypyc compiles type-annotated Python to C — good fit if you already use mypy.
Q91. What does PEP 659 / specializing adaptive interpreter (3.11+) do?
The interpreter specializes hot bytecode based on observed types. Result: Python 3.11 is ~25% faster than 3.10 on most workloads with zero code changes.
Q92. What is __pycache__?
Directory where Python caches compiled .pyc bytecode. Speeds up subsequent imports. Safe to delete; will be regenerated.
Section 7: Testing and Debugging
Q93. What is the difference between unittest and pytest?
unittest ships with Python and uses class-based test cases (xUnit style). pytest is a third-party framework with function-based tests, powerful fixtures, parametrization, and better failure output. Most modern Python projects use pytest.
Q94. What is a fixture in pytest?
A reusable setup function that pytest injects into tests by name. Replaces setUp/tearDown with composable, scoped (function/class/module/session) helpers.
Q95. What is unittest.mock and when do you patch?
Library for replacing objects with mocks during tests. Patch the place where the object is used, not where it's defined: @patch("myapp.module.requests"), not @patch("requests").
Q96. What is parametrized testing?
@pytest.mark.parametrize("input,expected", [
(1, 1), (2, 4), (3, 9),
])
def test_square(input, expected):
assert square(input) == expected
Q97. What is a property-based test (Hypothesis)?
Instead of writing example inputs, you describe properties the code should satisfy and Hypothesis generates inputs to break it. Catches edge cases you wouldn't think of.
Q98. How do you debug a Python program?
breakpoint() (3.7+) drops into pdb. pdb.set_trace() for older versions. IDE debuggers wrap pdb with a GUI. logging is the boring but most-used answer.
Q99. logging vs print?
Logging gives you levels (DEBUG, INFO, WARNING, ERROR), structured handlers (file, syslog, JSON), timestamps, and can be turned off without code changes. Use it for anything more permanent than throwaway debugging.
Q100. What is type-checking with mypy?
Static type checker that reads type hints and catches type errors before runtime. Run in CI alongside tests. Strict mode (--strict) is harsh but pays off in large codebases.
Section 8: Python Coding Problems
Q101. Reverse a string without using built-ins.
def reverse(s):
result = []
for ch in s:
result.insert(0, ch)
return "".join(result)
# O(n²) due to insert(0). Better:
def reverse(s):
chars = list(s)
i, j = 0, len(chars) - 1
while i < j:
chars[i], chars[j] = chars[j], chars[i]
i, j = i + 1, j - 1
return "".join(chars)
Q102. Check if a string is a palindrome (Pythonic).
def is_palindrome(s: str) -> bool:
s = "".join(c.lower() for c in s if c.isalnum())
return s == s[::-1]
Q103. Find the first non-repeating character.
from collections import Counter
def first_unique(s):
counts = Counter(s)
for ch in s:
if counts[ch] == 1: return ch
return None
# O(n) time, O(1) space (assuming bounded alphabet)
Q104. Fibonacci with memoization.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n - 1) + fib(n - 2)
# O(n) time and space
Q105. Implement a thread-safe singleton.
import threading
class Singleton:
_instance = None
_lock = threading.Lock()
def __new__(cls):
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
Q106. Two Sum.
def two_sum(nums, target):
seen = {}
for i, n in enumerate(nums):
if target - n in seen:
return [seen[target - n], i]
seen[n] = i
# O(n) time, O(n) space
Q107. Group anagrams.
from collections import defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for word in words:
groups[tuple(sorted(word))].append(word)
return list(groups.values())
Q108. Validate brackets.
def is_valid(s):
stack, pairs = [], {")": "(", "}": "{", "]": "["}
for ch in s:
if ch in "({[":
stack.append(ch)
elif not stack or stack.pop() != pairs[ch]:
return False
return not stack
Q109. Implement an LRU cache.
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity):
self.cache, self.capacity = OrderedDict(), capacity
def get(self, key):
if key not in self.cache: return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key, value):
if key in self.cache: self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
# O(1) for both operations
Q110. Flatten nested list (any depth).
def flatten(nested):
for item in nested:
if isinstance(item, list):
yield from flatten(item)
else:
yield item
# list(flatten([1, [2, [3, [4]]], 5])) → [1, 2, 3, 4, 5]
How to Use This Guide
Don't read it cover-to-cover. Pick a section a day, code each example yourself in a REPL, and write down the questions you couldn't answer cleanly. Then revisit them weekly until the answer is automatic. Interviewers can tell within 30 seconds whether you've memorized an answer or actually internalized it.
Practice with InterviewCodeAssist
The questions above cover the "what." Real interviews test the "how" — explaining your thinking out loud while typing. InterviewCodeAssist watches your editor and gives you real-time Python-specific guidance: idiomatic patterns, complexity analysis, edge-case hints. Pair it with the questions above to convert memorization into genuine fluency.
Related Reading
Ready for your interview and meeting copilot?
Live Audio Sessions, resume + JD personalized answers, and a quiet-transcription mode for meetings.
Try InterviewCodeAssist free↓