Skip to main content
HireInterviewAIHireInterviewAI
ProductAI & MLProctoringPricingSkillsBlogDevelopers
Log inBook a Demo
  1. Home
  2. Blog
  3. How to interview a Python developer: a concept-by-concept guide

Role Guide

How to interview a Python developer: a concept-by-concept guide

How to interview a Python developer concept by concept — the object model, the data model, generators, decorators, EAFP, and the GIL — to measure real depth, not syntax recall.

HireInterviewAI Team·July 9, 2026·7 min read
An interviewer testing a Python developer with object-model, data-model, generator, and GIL probes
On this page
  • Why "it runs" isn't Python knowledge
  • The concepts that separate real Python engineers
  • 1. The object & reference model
  • 2. The data model (dunder protocols)
  • 3. Generators & iteration
  • 4. Decorators & closures
  • 5. EAFP & context managers
  • 6. Concurrency, async & the GIL (the ceiling probe)
  • What a Python depth report looks like
  • Mastery vs bluffing: the pattern

On this page

  • Why "it runs" isn't Python knowledge
  • The concepts that separate real Python engineers
  • 1. The object & reference model
  • 2. The data model (dunder protocols)
  • 3. Generators & iteration
  • 4. Decorators & closures
  • 5. EAFP & context managers
  • 6. Concurrency, async & the GIL (the ceiling probe)
  • What a Python depth report looks like
  • Mastery vs bluffing: the pattern
HireInterviewAI Team

Written by

HireInterviewAI Team

AI Interview Research

The HireInterviewAI team builds adaptive AI technical interviews that probe candidates concept by concept and report exactly which topics they understand at depth.

hireinterviewai.com

HireInterviewAI

See what HireInterviewAI's per-concept interviews reveal

Stop hiring on a single fuzzy score. Run a live, adaptive AI technical interview that probes each concept to its ceiling and reports exactly which topics a candidate understands at depth.

See what HireInterviewAI's per-concept interviews revealExplore the developer API

Related reading

  • Role Guide

    How to interview a Kubernetes engineer: a concept-by-concept guide

    How to interview a Kubernetes engineer concept by concept — reconciliation, scheduling, networking, RBAC, and security probes that separate real depth from kubectl fluency.

    Read
  • Role Guide

    How to interview a backend developer: a concept-by-concept guide

    How to interview a backend developer concept by concept — APIs, databases, concurrency, system design, reliability — to measure true depth, not vibes.

    Read
  • Concept Guide

    How to test Go concurrency knowledge in an interview

    How to test Go concurrency knowledge with real interview probes — goroutines, channels, context, the data race — and tell mastery from confident bluffing.

    Read
HireInterviewAIHireInterviewAI

AI-powered technical interviews that help engineering teams hire smarter, faster, and without bias.

Product

  • Features
  • Pricing
  • Security
  • Changelog

Company

  • About
  • Blog
  • Careers
  • Contact

Resources

  • Documentation
  • API Reference
  • Skill assessments
  • Status

Legal

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • GDPR

© 2026 HireInterviewAI, Inc. All rights reserved.

Built for engineers who deserve better interviews

Key takeaways
  • Python's readability makes shallow understanding look deep — a green test suite tells you the code ran, not whether the candidate understands references, the data model, or the GIL.
  • Probe six concepts: the object/reference model, the data model, generators, decorators & closures, EAFP & context managers, and concurrency & the GIL. Each has a clean "understands it" vs "memorized syntax" tell.
  • Mastery shows up as reasoning about what actually happens — a shared default list, a one-shot generator, a late-binding closure, the GIL serializing threads — not reciting that "Python is dynamically typed".
  • Adaptive, per-concept probing reveals each candidate's real ceiling on each concept instead of one misleading score.

To interview a Python developer well, you have to get past the surface fluency — "everything is an object," "list comprehensions are Pythonic" — that anyone who has written Python for a month can recite, and probe whether they can reason about what actually happens: shared references, a one-shot generator, a late-binding closure, the GIL serializing threads. This guide gives you specific probes for six concepts and, for each, the difference between a developer who understands Python and one who has memorized its syntax.

Why "it runs" isn't Python knowledge

Python's greatest strength in an interview is also its trap: it reads like pseudocode, so working code looks like understanding. A candidate who writes clean, passing Python can still ship a mutable-default-argument bug that corrupts state across calls, or thread a CPU-bound workload that runs slower than the serial version. Those bugs don't show up in a green test run — they show up in production.

It's also the easiest language to bluff. The syntax is forgiving, the idioms are memorable, and "Pythonic" is easy to say. So the interview can't be "reverse a string." It has to be "what actually happens when this runs, and why?"

The concepts that separate real Python engineers

1. The object & reference model

Probe: "def append_to(item, target=[]): target.append(item); return target. A colleague calls it three times, each with just a new item. What comes back each time, and why?"

  • Mastery: [a], then [a, b], then [a, b, c] — the default list is created once, when the def executes, and shared by every call that uses the default. Explains Python's model: names are references bound to objects, and the default is one object living on the function. Reaches for the None-sentinel fix (target=None; if target is None: target = []), and connects it to is vs == and aliasing — mutating through one name is visible through every name pointing at the same object.
  • Bluffing: Expects [a], [b], [c] — a fresh list each call — or says "Python makes a new default every time." This is the single most revealing Python miss.

2. The data model (dunder protocols)

Probe: "You give a class a custom __eq__ so two Points with the same coordinates compare equal. Then you put Points in a set and use them as dict keys — and it breaks. What happened?"

  • Mastery: Defining __eq__ sets __hash__ to None, so the instances become unhashable and a set/dict raises TypeError. You have to define a consistent __hash__ over the same fields — and only for an immutable value object, because a mutable key whose hash changes is a bug. Knows the contract: objects that compare equal must hash equal. Often reaches for @dataclass(frozen=True) and treats the data model (__eq__, __hash__, __len__, __getitem__) as the surface that makes a class behave like a built-in.
  • Bluffing: Thinks __eq__ alone is enough; doesn't know that defining it removes the default __hash__; has never heard of the equal-implies-equal-hash contract.

3. Generators & iteration

Probe: "A function returns a generator over a big file. You pass it to sum(), then to max(). sum gives a number; max raises a ValueError about an empty sequence. Why?"

  • Mastery: A generator is a one-shot iterator — sum() consumes it to exhaustion, so max() sees nothing left. Explains lazy evaluation (constant memory, works on huge or infinite streams) and the fix: materialize with list() if you need multiple passes, or rebuild the generator. Knows a generator expression is lazy where a list comprehension is eager (memory vs reuse), and flags the iterate-while-mutating trap.
  • Bluffing: Treats the generator like a reusable list, doesn't know it's exhausted after one pass, and "just call it twice" without realizing the generator object is spent.

4. Decorators & closures

Probe: "handlers = [lambda: i for i in range(3)]. You call each one. They all return 2. Why, and how do you fix it?"

  • Mastery: Closures capture the variable, not its value at creation time — they hold a reference to the enclosing binding, and by the time you call them the loop has finished with i == 2, so all three see 2 (late binding). Fixes it by binding per-iteration: lambda i=i: i, or functools.partial. Connects this to decorators (which are closures) and why functools.wraps matters — it preserves __name__/__doc__/__wrapped__ so the decorated function stays debuggable.
  • Bluffing: Expects [0, 1, 2], can't explain why they're all 2, and thinks each lambda "remembers" its own i.

5. EAFP & context managers

Probe: "A candidate writes if os.path.exists(path): with open(path) as f: ... else: handle_missing(). What's the idiomatic critique, and what's the subtle bug?"

  • Mastery: That's LBYL (look before you leap), and it opens a TOCTOU race — the file can vanish or appear between the exists() check and the open(). The Pythonic pattern is EAFP: try: open(path) except FileNotFoundError: ... — race- free and idiomatic ("easier to ask forgiveness than permission"). Explains that with guarantees the file closes even on exception (the context-manager protocol), knows how to write one (contextlib.contextmanager), and avoids catching bare Exception.
  • Bluffing: Sees nothing wrong, defends the check-then-open, has never heard of EAFP or the race, and reaches for a bare except:.

6. Concurrency, async & the GIL (the ceiling probe)

Probe: "To speed up a CPU-bound function you run it across four threads. It's no faster — sometimes slower. Why? And if the workload were four API calls instead, would threads help?"

  • Mastery: The GIL lets only one thread execute Python bytecode at a time, so CPU-bound work doesn't parallelize across threads; the lock contention and context-switching make it slightly slower. For CPU work you reach for multiprocessing / a ProcessPoolExecutor / a C extension (NumPy releases the GIL). For the four API calls — I/O-bound — threads do help, because the GIL is released during blocking I/O, so the waits overlap (asyncio does the same cooperatively). Bonus: the async version of this exact bug is a blocking call inside a coroutine freezing the event loop (fix: run_in_executor / asyncio.to_thread).
  • Bluffing: "More threads = faster," doesn't know the GIL exists, and can't tell a CPU-bound workload from an I/O-bound one — so prescribes threads for the case where they can't possibly help.

What a Python depth report looks like

Interviewed this way, a candidate doesn't get one Python score — they get a profile that tells you exactly what to trust and what to verify in onboarding:

Concept depth report

Python · 'senior' backend candidate, depth view

Data model & dunder protocols8/10
Decorators & closures7/10
Generators & iteration6/10
EAFP & error handling5/10
Concurrency, async & the GIL3/10

This candidate would sail through most take-home Python screens — their grasp of the data model and decorators is genuinely strong. The depth view surfaces the risk you'd otherwise find in production: a shaky mental model of the GIL and async, exactly the gap that ships a CPU-bound service pinned at one core or an event loop that stalls under load. That's a hire-with-a-known-gap, not a guess. A single "Python: 6.5/10" would have hidden both the strength and the risk. (Here's why one number is useless.)

Mastery vs bluffing: the pattern

Across all six concepts the tell is the same. Bluffers describe what things are ("a generator is lazy," "decorators wrap a function"). Developers who actually understand Python describe what happens and why — the default list shared across calls, the generator spent after one pass, the closure that captured a variable, the GIL serializing four threads — and how they'd catch it. Mechanism reasoning is the signal. Vocabulary is noise.

That's also why a fixed question can't carry the interview: a strong developer clears your first probe instantly and you learn nothing about their ceiling. You have to keep raising difficulty — which is precisely what an adaptive interview does automatically, finding each candidate's real boundary on each concept instead of stopping at the first correct answer.

HireInterviewAI probes concepts like these adaptively and reports the per-concept depth above instead of a pass/fail. See the Python assessment, the sibling guide to interviewing a backend developer, or the framework for how to evaluate developer skills.

Frequently asked questions

What is the single best question to interview a Python developer?
The mutable-default-argument question — a function with `def f(x, target=[])` called several times. It instantly separates developers who understand that the default list is created once and shared across calls (Python's reference model) from those who assume a fresh list each call, and it opens naturally into identity, aliasing, and the None-sentinel fix.
How do you assess Python depth without just running code?
Probe the reasoning behind the behavior, not the syntax: why a default list is shared, why a set of custom objects needs a consistent __hash__, why a generator is empty on the second pass, why four threads don't speed up CPU work. Candidates read and run real Python in-browser, and adaptive follow-ups find where genuine understanding ends.
Which Python concepts matter most for a senior hire?
Concurrency and the GIL, the data model, and typing discipline — the concepts a passing take-home barely touches but that cause the most expensive production incidents (a CPU-bound service pinned at one core, a stalled event loop, an unhashable-key crash). Fundamentals like comprehensions and slicing are table stakes; how someone reasons about references, laziness, and the GIL is what separates senior engineers.
How do you tell mastery from memorized syntax?
Push past definitions to mechanism. Bluffers describe what a generator or decorator is; developers who know Python describe what happens when it runs — the shared default, the exhausted iterator, the late-binding closure, the GIL serializing threads — and name the tool that catches it. Reasoning about what actually executes is the reliable tell.

Interview for what actually happens when the code runs, not what they can recite — and report it per concept so you know exactly what you're hiring. See how HireInterviewAI does it on the Python assessment, or check pricing.