Python Interview Playbook Python interview rehearsal: what each level is expected to know, a 55-question bank with strong-answer checklists, 20 predict-the-output puzzles with explanations, live-coding tasks, production scenarios, cheat sheets, common mistakes, and a 7-day study plan.
The other pages teach the material.
This page is for rehearsal: a question bank with what a strong answer contains, predict-the-output puzzles (every output below was verified on CPython 3.14), coding tasks that come up in live rounds, and a study plan.
What Interviewers Look For
Question Bank
Predict the Output
Live Coding Tasks
Production Scenarios
Cheat Sheets
Common Mistakes
Study Plan
Level Expected New grad / campus Built-in types, mutability, list vs tuple vs dict vs set, slicing, comprehensions, functions and *args, basic OOP, exceptions, output questions Mid Closures, decorators, generators, context managers, dunder methods, super() and MRO, complexity of built-ins, the GIL, threads vs processes, pytest, NumPy basics for data roles Senior Memory management and GC, descriptors, metaclass alternatives, asyncio internals and pitfalls, profiling, packaging, typing with generics and Protocols, API and service design in Python Staff / platform Free-threading and subinterpreter trade-offs, C extension and Rust interop, performance at scale, dependency and supply-chain management, migration strategy across versions
Signals that raise your rating: explaining why (for example, why a mutable default is shared), quoting Big-O of built-ins without hesitation, writing idiomatic code (enumerate, zip, comprehensions, with), and knowing what changed in recent versions.
# Question Strong answer includes Read 1 Is Python compiled or interpreted? Bytecode compile, VM, .pyc, specializing interpreter, JIT Fundamentals 2 Mutable vs immutable types? Lists, dicts, sets vs ints, strs, tuples; rebinding vs mutation Fundamentals 3 is vs ==?Identity vs equality, singletons, small int cache trap Fundamentals 4 How are arguments passed? Object references by value, mutation visible, rebinding not Fundamentals 5 Shallow vs deep copy? Shared inner objects, copy.deepcopy, memo for cycles Fundamentals 6 Mutable default argument bug? Evaluated once at def, None sentinel fix Fundamentals 7 What is falsy in Python? None, zeros, empty containers, __bool__ / __len__Fundamentals 8 How does match differ from switch? Structural destructuring, capture patterns, guards Fundamentals 9 Exception hierarchy and best practice? BaseException vs Exception, narrow catches, raise fromFundamentals 10 EAFP vs LBYL? Try and handle vs check first, race conditions Fundamentals 11 What does if __name__ == "__main__" do? Module name when run vs imported, multiprocessing spawn Fundamentals 12 How do imports work? sys.modules cache, sys.path, circular importsFundamentals
# Question Strong answer includes Read 13 How is a list implemented? Array of pointers, over-allocation, amortized append, O(n) front ops Data Structures 14 How is a dict implemented? Compact hash table, open addressing, insertion order since 3.7 Data Structures 15 List vs tuple? Mutability, hashability, memory, intent Data Structures 16 What can be a dict key? Hashable, __hash__ consistent with __eq__ Data Structures 17 Complexity of x in list vs x in set? O(n) vs O(1) average, worst case with collisions Data Structures 18 When to use deque? O(1) both ends, BFS, maxlen windows Data Structures 19 How do you implement a priority queue? heapq, tuples with tie-breakers, max-heap trick, 3.14 max functionsData Structures 20 Counter and defaultdict use cases?Frequencies, grouping, factory semantics Data Structures 21 Comprehension vs generator expression? Eager vs lazy, memory, single pass Data Structures 22 How does sorting work? Timsort, stable, key=, multi-key tuples Data Structures
# Question Strong answer includes Read 23 *args, **kwargs, /, * in signatures?Parameter kinds, forwarding, keyword-only design Functions 24 Explain LEGB and nonlocal. Compile-time scoping, UnboundLocalError Functions 25 What is a closure? Cells, late binding, default-argument fix Functions 26 Write a decorator with arguments. Three levels, functools.wraps Functions 27 Iterator vs iterable vs generator? Protocols, single pass, lazy evaluation Functions 28 yield vs return, and yield from?Suspended frames, send, delegation, return value Functions 29 How does with work? __enter__ / __exit__, exception suppression, contextmanagerFunctions 30 lru_cache pitfalls?Hashable args, memory growth, methods keep self alive Functions
# Question Strong answer includes Read 31 __new__ vs __init__?Creation vs initialization, immutables, singletons OOP 32 Class vs instance attributes? Lookup order, shared mutable class attribute bug OOP 33 classmethod vs staticmethod?Alternative constructors, subclass-friendly OOP 34 How do super() and the MRO work? C3, next in MRO, cooperative inheritance OOP 35 Why does __eq__ affect hashing? __hash__ = None, equal objects equal hashesOOP 36 What is a descriptor? __get__ / __set__, property, methods, lookup precedenceOOP 37 Dataclass vs NamedTuple vs Pydantic? Generated methods, immutability, validation OOP 38 What are metaclasses, and alternatives? type, class creation, __init_subclass__, decoratorsOOP
# Question Strong answer includes Read 39 What is the GIL? One thread runs bytecode, why it exists, released on I/O Internals 40 Does the GIL make code thread-safe? No, += interleaving, locks Internals 41 How is memory managed? Refcounting, cycle GC, generations, pymalloc Internals 42 What is free-threaded Python? PEP 703, 3.13 experimental, 3.14 supported, costs Internals 43 Why is Python slow, and how do you speed it up? Boxing, dynamic dispatch; algorithm, built-ins, NumPy, native code Internals 44 How do you profile? cProfile, py-spy, tracemalloc, measure firstInternals 45 Threads vs processes vs asyncio? I/O vs CPU bound, scale, shared state Concurrency 46 How does the event loop work? Cooperative, await points, epoll / kqueue Concurrency 47 gather vs TaskGroup?Structured concurrency, cancellation, ExceptionGroup Concurrency 48 Blocking call inside async code? Loop freezes, to_thread, async libraries Concurrency 49 How do you limit concurrency? Semaphore, bounded queues, worker poolsConcurrency 50 How do you manage dependencies? venv, pyproject.toml, lock files, uv Typing and Tooling
# Question Strong answer includes Read 51 Why is NumPy faster than lists? Contiguous typed buffer, C loops, SIMD, GIL released NumPy 52 Explain broadcasting. Compare from the right, equal or 1, stride 0, keepdims NumPy 53 View vs copy? Slices and reshapes view, masks and fancy indexing copy, shares_memory NumPy 54 What does axis=0 do? Collapses rows, one result per column NumPy 55 How do you speed up slow pandas code? Vectorize instead of apply / iterrows, dtypes, Copy-on-Write, Polars or DuckDB NumPy
Say the answer out loud before opening the explanation in your head.
# Code Output Why 1 a = [1, 2, 3]; b = a; a = a + [4]; print(b)[1, 2, 3]+ builds a new list and rebinds a2 a = [1, 2, 3]; b = a; a += [4]; print(b)[1, 2, 3, 4]+= on a list mutates in place (__iadd__)3 print({True: "a", 1: "b"}){True: 'b'}True == 1 and equal hashes, first key kept, last value wins4 print(round(2.5), round(3.5))2 4Banker's rounding 5 print(-7 // 2, -7 % 2)-4 1Floor toward negative infinity 6 g = (x for x in [1, 2]); print(list(g), list(g))[1, 2] []Generators are single pass 7 x = [1, 2, 2, 3] then remove every 2 inside for i in x[1, 2, 3]Removing shifts items, so the loop skips the second 2 8 print(bool("False"), [] == False)True FalseNon-empty string is truthy; [] is falsy but not equal to False 9 class A: x = 1 / class B(A): pass / B.x = 2; print(A.x, B.x)1 2Assignment on B creates B.x, shadowing A.x 10 x = [0, 1, 2]; x[1:2] = [7, 8, 9]; print(x)[0, 7, 8, 9, 2]Slice assignment can change length 11 print((1) * 3, (1,) * 3)3 (1, 1, 1)Parentheses alone do not make a tuple 12 it = iter([1, 2, 3]); print(2 in it, list(it))True [3]in consumed the iterator up to the match13 print([lambda: i for i in range(3)][0]())2Late binding: i is read at call time 14 def f(x, l=[]): l.append(x); return l / print(f(1), f(2))[1, 2] [1, 2]Shared default, and both prints show the same list 15 t = (1, [2]); t[1].append(3); print(t)(1, [2, 3])The tuple is immutable, its list is not 16 print(0 or [] or {} or "done")doneor returns the first truthy operand17 print([1, 2, 3][-4:10])[1, 2, 3]Slices clamp out-of-range bounds 18 print({**{"a": 1}, "a": 2}){'a': 2}Later keys win 19 m = [[0] * 3] * 3; m[0][0] = 1; print(m)[[1, 0, 0], [1, 0, 0], [1, 0, 0]]Three references to one inner list 20 print([] is [], () is ())False TrueNew lists each time; the empty tuple is a shared singleton (implementation detail)
Diamond MRO, a favorite follow-up:
class A : pass
class B ( A ): pass
class C ( A ): pass
class D ( B , C ): pass
print ([k. __name__ for k in D. __mro__ ]) # ['D', 'B', 'C', 'A', 'object']
Exception in finally:
def f ():
try :
return "try"
finally :
print ( "finally runs first" )
print (f()) # prints "finally runs first", then "try"
Practice these until you can write them without looking.
Task Key idea Word frequency, top k Counter(words).most_common(k) or a size-k heapGroup anagrams defaultdict(list) keyed by "".join(sorted(w)) or a count tupleLRU cache OrderedDict with move_to_end and popitem(last=False) (example )Flatten nested lists Recursive generator with yield from Timing / retry decorator functools.wraps, three-level factory for argumentsRate limiter Token bucket with time.monotonic() and a lock Chunk an iterable itertools.batched (3.12) or islice in a loopRead a huge file, count errors Iterate the file object line by line, generator pipeline Concurrent URL fetcher ThreadPoolExecutor or asyncio + SemaphoreMerge k sorted lists heapq.merge or a heap of (value, list_index, element_index)Implement an iterator class __iter__ returns self, __next__ raises StopIterationContext manager timer Class with __enter__ / __exit__ or @contextmanager
def flatten (items):
for x in items:
if isinstance (x, ( list , tuple )):
yield from flatten(x)
else :
yield x
list (flatten([ 1 , [ 2 , [ 3 , ( 4 , 5 )]], 6 ])) # [1, 2, 3, 4, 5, 6]
import threading, time
class TokenBucket :
def __init__ (self, rate: float , capacity: int ) -> None :
self .rate, self .capacity = rate, capacity
self .tokens = float (capacity)
self .updated = time.monotonic()
self .lock = threading.Lock()
def allow (self) -> bool :
with self .lock:
now = time.monotonic()
self .tokens = min ( self .capacity, self .tokens + (now - self .updated) * self .rate)
self .updated = now
if self .tokens >= 1 :
self .tokens -= 1
return True
return False
For algorithm rounds, see the Python templates on the Data Structures page and the DSA patterns .
Scenario Strong answer A FastAPI endpoint is slow under load, CPU is low Something blocks the event loop (sync DB driver, requests, time.sleep); find it with py-spy dump or asyncio debug mode; switch to async clients or to_thread Worker memory grows until OOM-killed Compare tracemalloc or memray snapshots; look for unbounded caches, lru_cache on methods, global lists, retained tracebacks; bound or evict CPU-bound batch job uses one core GIL; move to ProcessPoolExecutor with sensible chunksize, vectorize with NumPy or Polars, or try the free-threaded build if dependencies support it Works locally, ModuleNotFoundError in prod Different interpreter or environment; pin with a lock file, build a wheel or container, run python -m so sys.path is right Intermittent wrong counters under threads Unsynchronized read-modify-write; add a Lock, or use a queue.Queue and a single writer Process hangs after fork on Linux Forked while another thread held a lock; use spawn or forkserver (default since 3.14) Service slow to start python -X importtime to find heavy imports; lazy-import in functions (explicit lazy imports arrive in 3.15)Upgrading from 3.9 to 3.14 3.9 is end-of-life; run tests with warnings as errors, check removed modules (PEP 594), rebuild C extensions, adopt Ruff's pyupgrade rules
Operation Cost list.append, list.pop()O(1) amortized list.insert(0, x), list.pop(0), x in listO(n) dict[k], k in dict, set.add, x in setO(1) average deque.appendleft, deque.popleftO(1) heappush, heappopO(log n) heapifyO(n) sorted, list.sortO(n log n) str.join(parts)O(total length)
Workload Tool Few blocking I/O calls ThreadPoolExecutorThousands of sockets asyncioCPU-bound pure Python ProcessPoolExecutor / InterpreterPoolExecutorNumeric arrays NumPy (releases the GIL)
Syntax Method len(x)__len__x[i]__getitem__x()__call__with x__enter__, __exit__for a in x__iter__, __next__x == y__eq__hash(x)__hash__repr(x)__repr__
Using a mutable default argument.
Using is to compare numbers or strings.
Saying Python "passes by reference".
Saying the GIL makes code thread-safe, or that threads never help (they do for I/O).
Calling list.sort() and assigning its None result.
Using list.pop(0) in a BFS instead of deque.popleft().
Forgetting functools.wraps in decorators.
Catching bare except: or swallowing CancelledError.
Calling blocking libraries inside async def.
Confusing type hints with runtime validation.
Iterating a generator twice.
Defining __eq__ and being surprised the object is unhashable.
Day Focus Output 1 Fundamentals Explain names vs objects and mutability; solve all 20 output puzzles 2 Data Structures Recite the complexity table; write BFS, Dijkstra, and LRU from memory 3 Functions Write a retry decorator with arguments, a generator pipeline, and a context manager 4 OOP Build a Vector with dunders; explain a diamond MRO; write a validating descriptor 5 Internals Explain refcounting, GC, and the GIL in two minutes each; profile a script with cProfile 6 Concurrency and, for data roles, NumPy Write a bounded async fetcher and a process-pool job; solve the NumPy output table 7 Typing and Tooling and this pageSet up a uv project with pytest and Ruff; answer the question bank out loud
Related: Java for comparing language designs, OOPS for principles, Backend for building services, and Operating Systems for what threads and processes are underneath.