Skip to content
Preptima

Python interview questions and answers

Python for backend, automation, and data roles, including the runtime behaviour that surprises candidates who only know the syntax.

22 published across 7 topics.

Core Python

3 questions

Data model, mutability, scoping, comprehensions, and the truthiness and copying gotchas.

mediumConcept

Why does `is` agree with `==` for some numbers and strings but not others?

Because `is` compares identity while `==` compares value, and CPython reuses objects for small integers and for compile-time string constants. The agreement is an implementation detail of the interpreter you happen to be running, so code that relies on it works until the values change. It also connects interning to the point an interviewer is testing.

5 minentry, mid, senior
All 3 in Core Python

OOP in Python

3 questions

Dunder methods, MRO and multiple inheritance, descriptors, dataclasses, and properties.

hardConcept

When would you reach for an abstract base class rather than a Protocol, and what does isinstance check in each case?

Use a Python ABC when you need nominal inheritance and runtime instantiation checks; use a Protocol when a type checker should accept any object with the required methods, even without inheritance. Use this abstract base classes answer to show the decision, trade-off, and evidence rather than a memorised definition. It also connects protocols to the point an interviewer is testing.

5 minmid, senior, staff
mediumConceptCoding

If you were writing a small value type in Python, which dunder methods would you implement, what would you let a dataclass generate, and how does super() decide what to call?

Implement the dunders that opt your type into a protocol, treating repr, eq and hash as one decision, and let a dataclass generate the boilerplate when the fields are the identity. super() follows the C3 linearisation of type(self), so it calls the next class in the MRO rather than your own base.

4 minmid, senior
hardConceptCoding

What is a descriptor, and how does @property use one?

A Python descriptor implements __get__, and optionally __set__ or __delete__, to control attribute access; @property is a data descriptor that wins over the instance dictionary.

5 minmid, senior, staff
All 3 in OOP in Python

Closures, laziness, context managers, and writing composable higher-order utilities.

mediumConceptCoding

When does a decorator actually run, and what goes wrong when you stack two of them?

Decoration runs once, at definition time, so it happens on import rather than on call. Stacked decorators apply bottom-up and execute outermost-first, and each wrapper replaces the function's identity unless functools.wraps restores it, which is what breaks introspection and framework registration.

5 minmid, senior
mediumConceptCoding

How do generators reduce memory use, and when are they the wrong choice?

A generator produces items on demand and keeps only the current item plus its suspended frame, so memory stays flat as the input grows; it is the wrong tool when you need a length, indexing, or more than one pass, and when per-item resume overhead outweighs the space saved.

5 minmid, senior, staff
All 3 in Decorators, Generators & Iterators

Threads versus processes versus asyncio, what the GIL actually blocks, and choosing per workload.

hardConceptScenario

An asyncio call times out and you handle the TimeoutError, but the background task keeps running and mutates shared state a few seconds later. What happened, and how do you make the timeout actually stop the work?

A timeout requests cancellation; it does not stop code. CancelledError is raised at the task next await point, so a task inside blocking code, shielded, in an executor thread, or swallowing the exception keeps running and commits its side effects late. Fix by re-raising CancelledError, keeping blocking calls off the loop, and using asyncio.timeout with a TaskGroup.

4 minmid, senior, staff
All 4 in Concurrency & the GIL

Reference counting, garbage collection, profiling, and where interpreter overhead dominates.

mediumConceptCoding

A list of a million small objects uses far more memory than the data inside them. Where is it going?

Into per-object overhead: in CPython on a 64-bit build every object carries a 16-byte header, every field is itself a boxed object reached through an 8-byte pointer, and each instance has a dictionary. Slots remove the dictionary, and a columnar layout removes the objects. Use this memory layout answer to show the decision, trade-off, and evidence rather than a memorised definition.

5 minmid, senior, staff
All 3 in Python Memory & Performance

Django & FastAPI

3 questions

ORM behaviour and N+1, middleware, dependency injection, async endpoints, and validation.

mediumConceptScenario

You cached something in a module-level dictionary. It works on your laptop and behaves oddly in production. What is different?

Production runs several worker processes, and each has its own interpreter, its own imported modules and therefore its own copy of that dictionary. Requests land on whichever worker is free, so a write in one is invisible to the others and every restart discards the lot. Use this wsgi asgi answer to show the decision, trade-off, and evidence rather than a memorised definition.

5 minmid, senior
All 3 in Django & FastAPI

pytest fixtures and parametrisation, mocking and patching boundaries, and coverage honestly read.

mediumConceptScenario

Your suite mocks the database, every test passes, and the release still broke. What should you have tested instead?

A mock encodes your belief about the collaborator, so asserting against it proves the code matches your belief rather than reality. Use autospec so signatures are checked, and put a small number of tests against the real engine at the boundary the mock replaced. Use this mocking answer to show the decision, trade-off, and evidence rather than a memorised definition.

5 minmid, senior, staff
All 3 in Testing in Python