PythonasyncioORM

Python Backend Interview Questions

Python backend interviews concentrate on a small number of places where the language surprises people, and almost every one of them has produced a real production incident somewhere. The GIL and what it actually constrains. The async event loop and what blocks it. ORM session lifecycle and connection ownership. Mutable default arguments. These are not trivia; they are the recurring causes of Python backend failures.

The most frequent weakness is a candidate who is fluent in Python the language and vague about Python the runtime. They can write elegant comprehensions and cannot say why a single synchronous database call inside an `async def` handler degrades every concurrent request on that worker. The interview targets that gap deliberately, because it is the gap that produces outages.

Written and reviewed by Sahil Srivastav

What the bar actually is

You should be able to state what the GIL does precisely — one thread executes Python bytecode at a time, which bounds CPU-bound threading and does not prevent data races on compound operations — and choose correctly between threads, processes and async for a given workload.

On frameworks, you are expected to understand the session and connection lifecycle rather than just the query API. Where a session begins and ends, what a detached instance is, what happens to a connection borrowed on a path that raises. These are the questions that separate people who have operated a Python service from people who have written one.

How the rounds are structured

Machine coding in Python

A small service, usually with a concurrency or idempotency twist. Clean code matters, but the follow-up about what happens on a repeated call matters more.

Language and runtime questions

The GIL, mutable defaults, generators and laziness, context managers, how exceptions interact with cleanup. Fast and mostly a filter, but the GIL answer is frequently probed deeply.

Async behaviour

What blocks the event loop, why `await` is not parallelism, how a blocking library call inside a coroutine affects unrelated requests. Increasingly the differentiating round for Python roles.

ORM and database lifecycle

SQLAlchemy or Django ORM: session scope, transaction boundaries, N+1 queries, and connection pool exhaustion under load.

What this interview bar tests

The GIL, stated precisely

It serialises bytecode execution, so CPU-bound threads do not scale — but it does not make `x += 1` atomic, and it does not block I/O concurrency. Both halves of that are asked.

What blocks the event loop

A synchronous database driver, a `requests` call, CPU work, or `time.sleep` inside a coroutine stalls every other task on that loop. The fix is an executor or an async driver, not more workers.

Session and connection ownership

Where the session is created, who closes it, and what happens on an exception. Most Python connection leaks are this question answered wrongly.

Bounded memory over elegance

Generators and server-side cursors over loading a full result set. The "works in dev, MemoryError for the biggest customer" failure is almost always a materialised query.

A preparation plan that works

  1. 1Write a small async service and deliberately block it: call a synchronous HTTP client inside a handler, then measure latency on an unrelated endpoint. Seeing the collateral damage once makes the explanation permanent.
  2. 2Reproduce a pool exhaustion: a handler that raises before closing its session, called a few more times than the pool size. Then fix it with a context manager. This is the single most common Python backend production bug.
  3. 3Write the mutable-default-argument bug and the late-binding closure bug yourself. They are asked constantly and are much easier to explain once seen.
  4. 4Take one ORM query that triggers N+1 and fix it with eager loading, checking the emitted SQL. "I would use `selectinload`" is a stronger answer when you have watched the query count drop.

Questions you should expect

Does the GIL make Python thread-safe?

No, and this is the question most often answered wrongly. The GIL guarantees one thread runs bytecode at a time, but a compound operation like `counter += 1` is several bytecodes and a thread switch can land in the middle, losing updates. You still need a lock for shared mutable state. What the GIL does prevent is CPU-bound scaling across threads.

Your async endpoint is slow and CPU is low. Why?

Something blocking is running on the event loop — a synchronous driver, a `requests` call, or CPU-bound work inside a coroutine. While it runs, no other task progresses, so latency rises across endpoints that share the loop. Measure loop lag, then move the blocking call to an executor or switch to an async driver.

Why does this function remember values between calls?

A mutable default argument. The default is evaluated once at function definition, so the same list or dict is reused across every call and accumulates. Use `None` as the default and build the container inside the body.

What is a DetachedInstanceError telling you?

That you are touching an attribute requiring a database round trip on an object whose session has closed — typically a lazy-loaded relationship accessed after the request scope ended. Either load what you need while the session is open, or widen the session scope deliberately rather than by accident.

Threads, processes or async for this workload?

Async for high-concurrency I/O with async-capable libraries. Threads for blocking I/O where no async driver exists, accepting the memory cost. Processes for CPU-bound work, because the GIL makes threads pointless there. The answer should name the workload characteristic, not the preference.

What gets candidates rejected

  • Saying the GIL makes shared state safe, or that it prevents all concurrency
  • Blocking the event loop and then adding workers instead of removing the blocking call
  • Leaking sessions on exception paths because cleanup is not in a context manager or `finally`
  • Loading an entire result set into memory and filtering in Python
  • Not knowing why a mutable default argument retains state
  • Claiming async expertise while describing `await` as parallelism
  • Ignoring N+1 queries because the ORM hides them and each query is individually fast

What to practise, in order

Database connection pool exhaustion

Connections leaked on exception paths and sessions returned still inside a transaction. Tests assert the lifecycle invariant, not the happy path.

Full result materialization heap spike

An endpoint whose memory scales with the customer's total history rather than the page requested. Tests assert bounded memory per request.

Pandas join fan-out and deduplication

A join that silently multiplies rows. The data-correctness bug that passes every type check and every happy-path test.

Message queue consumer idempotency and retry

At-least-once delivery handled properly, with duplicates and reordering driven by the test suite.

Practise in a real repository

Gronex ships broken backend repositories with failing test suites that encode the production invariant. You read the evidence, find the defect, and make the tests pass — which is what the round actually measures, rather than whether you can recite a definition.

FAQ

Is Python taken seriously for backend roles in India?

Yes, particularly in data-adjacent, ML-serving and API-heavy teams, and increasingly in fintech. The interview bar is the same; only the runtime specifics change. What differs is that Python candidates get asked about the GIL and async where Java candidates get asked about GC and the memory model.

How much asyncio do I need?

Enough to explain what blocks a loop and why `await` is cooperative rather than parallel. For FastAPI or aiohttp roles, considerably more: task lifecycle, cancellation, and why a pending task destroyed at shutdown produces a warning you should not ignore.

Will I be asked to write type hints?

Rarely required, usually welcomed. On a machine coding round they make your intent legible under time pressure, which helps the reviewer. Do not let them slow you down.

Does the no-GIL work change these answers?

Directionally, for CPU-bound threading. But interviews are about the runtime you will operate, and GIL-bound behaviour remains the default assumption in production today. Describe the mechanism and note the direction of travel rather than asserting a specific version's behaviour.

Related

Other preparation tracks