Interview Bank · 2026

🐍 Python

Idioms, OOP, generators, the GIL, and the gotchas that separate "I use Python" from "I know Python." Say each answer aloud before you reveal it.

Rapid-fire flashcards flip to check

Click a card. Answer first, in one breath, then reveal.

list vs tuple?
List = mutable, tuple = immutable (and hashable, so usable as dict keys).
click to flip
is vs ==?
== compares values; is compares identity (same object in memory).
click to flip
What is a generator?
A lazy iterator built with yield — produces values one at a time, no list in memory.
click to flip
*args vs **kwargs?
*args = extra positional args (tuple); **kwargs = extra keyword args (dict).
click to flip
What does a decorator do?
Wraps a function to add behaviour without changing its body — a function taking a function, returning one.
click to flip
List vs generator comprehension?
[...] builds the whole list now; (...) yields lazily, item by item.
click to flip
What is self?
The instance the method is called on — explicitly passed as the first parameter.
click to flip
Shallow vs deep copy?
Shallow copies the outer object but shares nested refs; deep (copy.deepcopy) duplicates all the way down.
click to flip
What is a context manager?
An object usable with with — runs setup on enter, guaranteed teardown on exit (e.g. closing a file).
click to flip
@staticmethod vs @classmethod?
Static gets no implicit arg; class gets cls (the class) and can build/alter class-level state.
click to flip

Core questions

How is Python's memory managed?

Automatically, via reference counting (each object tracks how many references point to it; at zero it's freed) plus a cyclic garbage collector for reference cycles that counting alone can't free. You don't free() anything; CPython does it for you.

What's the difference between a list and a NumPy array — and when does it matter?

A list holds arbitrary Python objects and is flexible but slow for math. A NumPy array is a typed, contiguous block — vectorised operations run in C, far faster. It matters the moment you do numerical work at scale (e.g. the embedding vectors in your RAG pipeline).

Explain mutable vs immutable, with examples.

Immutable objects can't change after creation: int, float, str, tuple, frozenset. Mutable ones can: list, dict, set. This drives behaviour: strings return new objects on "change", and mutable objects passed to functions can be modified in place.

How does exception handling work — and what's else/finally for?

try runs risky code; except catches specific errors; else runs only if no exception was raised; finally always runs (cleanup), exception or not. Catch specific exceptions, not bare except:.

What's the difference between append() and extend()?

append(x) adds one item (even if it's a list — it nests). extend(xs) adds each item of an iterable. [1,2].append([3,4]) → [1,2,[3,4]] vs extend → [1,2,3,4].

What are Python's data classes and why use them?

@dataclass auto-generates __init__, __repr__, __eq__ from typed fields — boilerplate-free data holders. They're the mental model for Pydantic models, which add validation on top.

How do you manage dependencies and environments?

A virtual environment (python -m venv .venv) isolates a project's packages; pip install adds them; pip freeze > requirements.txt pins them. In 2026, many teams use uv (a fast Rust-based installer/resolver) as a drop-in speed-up.

What does if __name__ == "__main__": do?

It runs the block only when the file is executed directly, not when it's imported as a module. __name__ is "__main__" for the entry script, otherwise the module's name. Lets a file be both runnable and importable.

Theory deep-cuts the "why"

What is the GIL, and how does it affect concurrency? theory

The Global Interpreter Lock lets only one thread execute Python bytecode at a time in CPython. So threads don't give you parallel CPU work — but they're fine for I/O-bound work (network, disk), where threads wait anyway. For CPU-bound parallelism, use multiprocessing (separate processes, separate GILs) or async for I/O. (2026: the experimental free-threaded build is changing this — see What's New.)

How does async/await actually work? theory

It's cooperative concurrency on a single thread. An async def is a coroutine; await yields control back to the event loop while waiting on I/O, letting other coroutines run. No threads, no GIL fight — one worker handles thousands of waiting requests. It speeds up I/O-bound code, not CPU-bound.

Explain duck typing and EAFP vs LBYL. theory

Duck typing: "if it walks like a duck…" — Python cares what an object can do, not its class. EAFP ("easier to ask forgiveness than permission") = try the operation, catch the error — the Pythonic style. LBYL ("look before you leap") = check first with if. EAFP is usually preferred and avoids race conditions.

What is the MRO (Method Resolution Order)? theory

The order Python searches base classes for a method, used to resolve multiple inheritance. It uses the C3 linearisation algorithm; you can inspect it with ClassName.__mro__. super() follows the MRO, not just the literal parent.

How do iterators and iterables differ? theory

An iterable has __iter__ and can produce an iterator (lists, strings). An iterator has __next__ and yields values one at a time, holding position. for calls iter() on the iterable, then next() until StopIteration. Generators are iterators.

Tricky & gotchas where candidates trip

Why is a mutable default argument dangerous? tricky

Default values are evaluated once, at definition time, and shared across calls. def f(x, items=[]): reuses the same list every call, so it accumulates. Fix: def f(x, items=None): items = items or []. A classic interview filter.

What does 0.1 + 0.2 == 0.3 return, and why? tricky

False — floats are binary approximations, so 0.1 + 0.2 is 0.30000000000000004. Compare with math.isclose(), or use decimal.Decimal for money.

What prints? for i in range(3): funcs.append(lambda: i) then call them. tricky

All print 2 (the final i) — closures capture the variable, not its value at creation (late binding). Fix with a default arg: lambda i=i: i.

a = b = [] — then a.append(1). What's b? tricky

b is [1]a and b are two names for the same list. Assignment binds names to objects; it doesn't copy. Same trap with mutable function arguments.

When is is with small ints misleading? tricky

CPython caches small ints (−5…256), so a = 256; b = 256; a is b is True, but 257 is 257 can be False across statements. Never use is for value comparison — only for None/singletons.

Why might modifying a list while iterating it break? tricky

The iterator's internal index gets out of sync with the changing length, so you skip elements or hit IndexError. Iterate over a copy (for x in items[:]) or build a new list with a comprehension.

What's new in 2026 say this and stand out

What changed with the GIL recently? 2026

Python 3.13 shipped an experimental free-threaded build (PEP 703) that can run without the GIL, enabling true multi-core threading; 3.14 advanced it toward officially supported. It's opt-in and still maturing — single-thread code can be a bit slower — but it's the biggest concurrency shift in Python's history. Knowing it exists signals you follow the ecosystem.

What's the experimental JIT? 2026

CPython 3.13 added an experimental JIT compiler (PEP 744) that compiles hot code paths to machine code at runtime. Early days and modest gains so far, but it's the foundation for future speedups. Pair it in your answer with the free-threading work as "CPython getting seriously faster."

Any new syntax worth knowing? 2026

3.12 introduced cleaner generic type-parameter syntax (def first[T](xs: list[T]) -> T:) and the type alias statement. 3.14 added t-strings (template strings, PEP 750) for safe, deferred string processing, and made annotations lazily evaluated by default. Also: modern tooling — uv for envs/installs and ruff for lint+format — is now the de-facto fast standard.

Memory hooks GIL = "one mic at a time." Threads pass the mic (good for waiting/I-O), processes each get their own mic (good for CPU).
EAFP = "just try it." LBYL = "check first." Pythonistas just try it.
Mutable default = "shared clipboard." Everyone scribbles on the same one.
Tie it to DocChat When asked "do you know Python?", don't recite — point: "I built DocChat's backend in Python — FastAPI routes, a chunking generator, the RAG pipeline." Concrete beats abstract.