Last Minute Notes

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.

📘 Python Interview Playbook

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.

Table of Contents

  1. What Interviewers Look For
  2. Question Bank
  3. Predict the Output
  4. Live Coding Tasks
  5. Production Scenarios
  6. Cheat Sheets
  7. Common Mistakes
  8. Study Plan

1. What Interviewers Look For

LevelExpected
New grad / campusBuilt-in types, mutability, list vs tuple vs dict vs set, slicing, comprehensions, functions and *args, basic OOP, exceptions, output questions
MidClosures, decorators, generators, context managers, dunder methods, super() and MRO, complexity of built-ins, the GIL, threads vs processes, pytest, NumPy basics for data roles
SeniorMemory management and GC, descriptors, metaclass alternatives, asyncio internals and pitfalls, profiling, packaging, typing with generics and Protocols, API and service design in Python
Staff / platformFree-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.


2. Question Bank

2.1 Language basics (12)

#QuestionStrong answer includesRead
1Is Python compiled or interpreted?Bytecode compile, VM, .pyc, specializing interpreter, JITFundamentals
2Mutable vs immutable types?Lists, dicts, sets vs ints, strs, tuples; rebinding vs mutationFundamentals
3is vs ==?Identity vs equality, singletons, small int cache trapFundamentals
4How are arguments passed?Object references by value, mutation visible, rebinding notFundamentals
5Shallow vs deep copy?Shared inner objects, copy.deepcopy, memo for cyclesFundamentals
6Mutable default argument bug?Evaluated once at def, None sentinel fixFundamentals
7What is falsy in Python?None, zeros, empty containers, __bool__ / __len__Fundamentals
8How does match differ from switch?Structural destructuring, capture patterns, guardsFundamentals
9Exception hierarchy and best practice?BaseException vs Exception, narrow catches, raise fromFundamentals
10EAFP vs LBYL?Try and handle vs check first, race conditionsFundamentals
11What does if __name__ == "__main__" do?Module name when run vs imported, multiprocessing spawnFundamentals
12How do imports work?sys.modules cache, sys.path, circular importsFundamentals

2.2 Data structures (10)

#QuestionStrong answer includesRead
13How is a list implemented?Array of pointers, over-allocation, amortized append, O(n) front opsData Structures
14How is a dict implemented?Compact hash table, open addressing, insertion order since 3.7Data Structures
15List vs tuple?Mutability, hashability, memory, intentData Structures
16What can be a dict key?Hashable, __hash__ consistent with __eq__Data Structures
17Complexity of x in list vs x in set?O(n) vs O(1) average, worst case with collisionsData Structures
18When to use deque?O(1) both ends, BFS, maxlen windowsData Structures
19How do you implement a priority queue?heapq, tuples with tie-breakers, max-heap trick, 3.14 max functionsData Structures
20Counter and defaultdict use cases?Frequencies, grouping, factory semanticsData Structures
21Comprehension vs generator expression?Eager vs lazy, memory, single passData Structures
22How does sorting work?Timsort, stable, key=, multi-key tuplesData Structures

2.3 Functions and iteration (8)

#QuestionStrong answer includesRead
23*args, **kwargs, /, * in signatures?Parameter kinds, forwarding, keyword-only designFunctions
24Explain LEGB and nonlocal.Compile-time scoping, UnboundLocalErrorFunctions
25What is a closure?Cells, late binding, default-argument fixFunctions
26Write a decorator with arguments.Three levels, functools.wrapsFunctions
27Iterator vs iterable vs generator?Protocols, single pass, lazy evaluationFunctions
28yield vs return, and yield from?Suspended frames, send, delegation, return valueFunctions
29How does with work?__enter__ / __exit__, exception suppression, contextmanagerFunctions
30lru_cache pitfalls?Hashable args, memory growth, methods keep self aliveFunctions

2.4 OOP (8)

#QuestionStrong answer includesRead
31__new__ vs __init__?Creation vs initialization, immutables, singletonsOOP
32Class vs instance attributes?Lookup order, shared mutable class attribute bugOOP
33classmethod vs staticmethod?Alternative constructors, subclass-friendlyOOP
34How do super() and the MRO work?C3, next in MRO, cooperative inheritanceOOP
35Why does __eq__ affect hashing?__hash__ = None, equal objects equal hashesOOP
36What is a descriptor?__get__ / __set__, property, methods, lookup precedenceOOP
37Dataclass vs NamedTuple vs Pydantic?Generated methods, immutability, validationOOP
38What are metaclasses, and alternatives?type, class creation, __init_subclass__, decoratorsOOP

2.5 Internals and concurrency (12)

#QuestionStrong answer includesRead
39What is the GIL?One thread runs bytecode, why it exists, released on I/OInternals
40Does the GIL make code thread-safe?No, += interleaving, locksInternals
41How is memory managed?Refcounting, cycle GC, generations, pymallocInternals
42What is free-threaded Python?PEP 703, 3.13 experimental, 3.14 supported, costsInternals
43Why is Python slow, and how do you speed it up?Boxing, dynamic dispatch; algorithm, built-ins, NumPy, native codeInternals
44How do you profile?cProfile, py-spy, tracemalloc, measure firstInternals
45Threads vs processes vs asyncio?I/O vs CPU bound, scale, shared stateConcurrency
46How does the event loop work?Cooperative, await points, epoll / kqueueConcurrency
47gather vs TaskGroup?Structured concurrency, cancellation, ExceptionGroupConcurrency
48Blocking call inside async code?Loop freezes, to_thread, async librariesConcurrency
49How do you limit concurrency?Semaphore, bounded queues, worker poolsConcurrency
50How do you manage dependencies?venv, pyproject.toml, lock files, uvTyping and Tooling

2.6 NumPy and data (5)

#QuestionStrong answer includesRead
51Why is NumPy faster than lists?Contiguous typed buffer, C loops, SIMD, GIL releasedNumPy
52Explain broadcasting.Compare from the right, equal or 1, stride 0, keepdimsNumPy
53View vs copy?Slices and reshapes view, masks and fancy indexing copy, shares_memoryNumPy
54What does axis=0 do?Collapses rows, one result per columnNumPy
55How do you speed up slow pandas code?Vectorize instead of apply / iterrows, dtypes, Copy-on-Write, Polars or DuckDBNumPy

3. Predict the Output

Say the answer out loud before opening the explanation in your head.

#CodeOutputWhy
1a = [1, 2, 3]; b = a; a = a + [4]; print(b)[1, 2, 3]+ builds a new list and rebinds a
2a = [1, 2, 3]; b = a; a += [4]; print(b)[1, 2, 3, 4]+= on a list mutates in place (__iadd__)
3print({True: "a", 1: "b"}){True: 'b'}True == 1 and equal hashes, first key kept, last value wins
4print(round(2.5), round(3.5))2 4Banker's rounding
5print(-7 // 2, -7 % 2)-4 1Floor toward negative infinity
6g = (x for x in [1, 2]); print(list(g), list(g))[1, 2] []Generators are single pass
7x = [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
8print(bool("False"), [] == False)True FalseNon-empty string is truthy; [] is falsy but not equal to False
9class 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
10x = [0, 1, 2]; x[1:2] = [7, 8, 9]; print(x)[0, 7, 8, 9, 2]Slice assignment can change length
11print((1) * 3, (1,) * 3)3 (1, 1, 1)Parentheses alone do not make a tuple
12it = iter([1, 2, 3]); print(2 in it, list(it))True [3]in consumed the iterator up to the match
13print([lambda: i for i in range(3)][0]())2Late binding: i is read at call time
14def 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
15t = (1, [2]); t[1].append(3); print(t)(1, [2, 3])The tuple is immutable, its list is not
16print(0 or [] or {} or "done")doneor returns the first truthy operand
17print([1, 2, 3][-4:10])[1, 2, 3]Slices clamp out-of-range bounds
18print({**{"a": 1}, "a": 2}){'a': 2}Later keys win
19m = [[0] * 3] * 3; m[0][0] = 1; print(m)[[1, 0, 0], [1, 0, 0], [1, 0, 0]]Three references to one inner list
20print([] 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"

4. Live Coding Tasks

Practice these until you can write them without looking.

TaskKey idea
Word frequency, top kCounter(words).most_common(k) or a size-k heap
Group anagramsdefaultdict(list) keyed by "".join(sorted(w)) or a count tuple
LRU cacheOrderedDict with move_to_end and popitem(last=False) (example)
Flatten nested listsRecursive generator with yield from
Timing / retry decoratorfunctools.wraps, three-level factory for arguments
Rate limiterToken bucket with time.monotonic() and a lock
Chunk an iterableitertools.batched (3.12) or islice in a loop
Read a huge file, count errorsIterate the file object line by line, generator pipeline
Concurrent URL fetcherThreadPoolExecutor or asyncio + Semaphore
Merge k sorted listsheapq.merge or a heap of (value, list_index, element_index)
Implement an iterator class__iter__ returns self, __next__ raises StopIteration
Context manager timerClass 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.


5. Production Scenarios

ScenarioStrong answer
A FastAPI endpoint is slow under load, CPU is lowSomething 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-killedCompare 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 coreGIL; 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 prodDifferent 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 threadsUnsynchronized read-modify-write; add a Lock, or use a queue.Queue and a single writer
Process hangs after fork on LinuxForked while another thread held a lock; use spawn or forkserver (default since 3.14)
Service slow to startpython -X importtime to find heavy imports; lazy-import in functions (explicit lazy imports arrive in 3.15)
Upgrading from 3.9 to 3.143.9 is end-of-life; run tests with warnings as errors, check removed modules (PEP 594), rebuild C extensions, adopt Ruff's pyupgrade rules

6. Cheat Sheets

Built-in complexity

OperationCost
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)

Concurrency choice

WorkloadTool
Few blocking I/O callsThreadPoolExecutor
Thousands of socketsasyncio
CPU-bound pure PythonProcessPoolExecutor / InterpreterPoolExecutor
Numeric arraysNumPy (releases the GIL)

Dunder quick map

SyntaxMethod
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__

7. Common Mistakes

  • 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.

8. Study Plan

DayFocusOutput
1FundamentalsExplain names vs objects and mutability; solve all 20 output puzzles
2Data StructuresRecite the complexity table; write BFS, Dijkstra, and LRU from memory
3FunctionsWrite a retry decorator with arguments, a generator pipeline, and a context manager
4OOPBuild a Vector with dunders; explain a diamond MRO; write a validating descriptor
5InternalsExplain refcounting, GC, and the GIL in two minutes each; profile a script with cProfile
6Concurrency and, for data roles, NumPyWrite a bounded async fetcher and a process-pool job; solve the NumPy output table
7Typing 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.

On this page