Boarding pass · Python Intermediate
Python · Intermediate interview
An AI mock interview for Python developers with a couple of years' experience. Go deeper into iterators and generators, decorators and closures, exceptions and context managers, and Python's data model.
- Voice interview
- Live feedback
- Browser-only
- No installation required
Your report · sample
AI Readiness Score
Finish the mock and get this report — scored on content and English, with concrete tips and a model answer for every question, plus a study plan.
Your flight path
Five steps to interview-ready.
From a quick warm-up to a personalised study plan — here's the whole loop, and what you get at each gate.
Step 01
Preparation
Skim the topics and warm up — you're briefed before takeoff.
Step 02
AI Interview
A realistic AI interviewer asks tailored questions — answer by voice or text.
Step 03
Instant Score
Finish and get a 0–100 readiness score across content and English.
Step 04
AI Feedback
Concrete tips and a rewritten model answer for every response.
Step 05
Study Plan
A personalised plan targets your weakest areas — so the next run scores higher.
Preview the AI demo
See one answer scored, end to end.
The whole loop on sample data — question, your answer, instant feedback and a study plan. Hover to pause.
Interviewer · Question 1
“Tell me about yourself.”
Who it's for
- Developers using Python daily
- Engineers writing reusable Python code
- Anyone targeting mid-level Python roles
- Devs sharpening before interviews
What you'll practice
- Writing generators and understanding laziness
- Decorators, closures and functools
- Exceptions, context managers and EAFP
- Dunder methods and the data model
Topics covered
What this level expects.
Iterators & generators
- Iterable vs iterator
- yield & laziness
- Generator expressions
Decorators & closures
- Decorators
- Closures & nonlocal
- functools
Errors & context
- try/except/else/finally
- Context managers
- EAFP vs LBYL
Data model
- Dunder methods
- Equality & hashing
- Copy semantics
Practice questions
12 questions, with model answers.
Read them, then run the live mock to answer out loud and get scored. Tap any question to reveal a model answer.
01What's the difference between an iterable and an iterator?Iterators & generators
An iterable is anything you can loop over — it implements __iter__ and returns an iterator (lists, dicts, strings). An iterator is the object that actually produces values one at a time via __next__, raising StopIteration when done, and is itself an iterable. So a list is iterable but not its own iterator; calling iter() on it gives you one.
02How does a generator work and why is it memory-efficient?Iterators & generators
A generator function uses yield to produce values lazily: calling it returns a generator object, and each next() runs the function until the next yield, suspending its state in between. Because it produces one value at a time instead of building a whole list, it uses constant memory and can represent infinite or huge sequences — ideal for streaming large files or pipelines.
def read_lines(path):
with open(path) as f:
for line in f:
yield line.strip()03When would you use a generator expression instead of a list comprehension?Iterators & generators
Use a generator expression (parentheses instead of brackets) when you don't need the whole list at once — for example, feeding sum() or any(), or processing a large stream. It produces items lazily and uses far less memory. Use a list comprehension when you need to index, reuse, or keep the full result.
total = sum(n*n for n in range(1_000_000)) # no million-item list
04How does a decorator work?Decorators & closures
A decorator is a callable that takes a function and returns a replacement, applied with @decorator syntax above the definition. It's typically used to wrap behaviour — logging, timing, caching, auth — around the original without changing its body. Inside, you define a wrapper that calls the original and add your behaviour around it.
def timed(fn):
@functools.wraps(fn)
def wrapper(*a, **k):
start = time.perf_counter(); r = fn(*a, **k)
print(time.perf_counter() - start); return r
return wrapper05What is a closure, and what does nonlocal do?Decorators & closures
A closure is a nested function that captures and remembers variables from its enclosing scope even after that scope has returned. Reading those variables works automatically; to reassign one you declare it nonlocal, otherwise Python treats the assignment as a new local. Closures are the mechanism behind decorators and stateful factory functions.
06What does functools.wraps and functools.lru_cache give you?Decorators & closures
functools.wraps copies the wrapped function's name, docstring, and metadata onto the wrapper so decorated functions still introspect correctly. functools.lru_cache memoizes a function's results keyed by its arguments, returning cached values for repeat calls — a one-line speedup for pure, expensive functions with hashable arguments. Both are staples of writing good decorators and fast code.
07How do try/except/else/finally work together?Errors & context
try holds the risky code; except handles specific exceptions; else runs only if no exception was raised (good for code that should only run on success); finally always runs, for cleanup, whether or not there was an error. Catching specific exception types rather than a bare except is important so you don't swallow bugs.
08What is a context manager and how do you write one?Errors & context
A context manager defines setup and teardown around a block via the with statement, guaranteeing cleanup even on exceptions — the classic example is with open(...) closing the file. You implement __enter__ and __exit__, or more simply write a generator decorated with @contextlib.contextmanager that yields once. It's the idiomatic way to manage resources like files, locks, and connections.
from contextlib import contextmanager
@contextmanager
def timer():
start = time.perf_counter()
try: yield
finally: print(time.perf_counter() - start)09What is EAFP versus LBYL in Python?Errors & context
EAFP — 'easier to ask forgiveness than permission' — means try the operation and catch the exception if it fails, which is the Pythonic default. LBYL — 'look before you leap' — checks preconditions first with ifs. EAFP avoids race conditions between the check and the action and is often cleaner, e.g. try/except KeyError instead of checking 'in' first.
10What are dunder methods, and which give you common behaviours?Data model
Dunder ('double underscore') methods let your objects hook into language syntax. __init__ initializes, __repr__/__str__ control representation, __eq__ defines equality, __len__ enables len(), __iter__ makes it iterable, __getitem__ enables indexing, and __enter__/__exit__ make it a context manager. Implementing the right ones makes your objects feel like built-ins.
11How are equality and hashing related, and why does it matter?Data model
If you define __eq__ so two objects can be equal, you must also define __hash__ consistently — equal objects must have equal hashes — or they'll misbehave as dict keys and set members. By default Python makes a class with a custom __eq__ unhashable unless you provide __hash__. Immutable value objects should hash on the same fields they compare.
12What's the difference between a shallow copy and a deep copy?Data model
A shallow copy (copy.copy, list slicing, dict.copy) duplicates the outer container but shares the nested objects, so mutating a nested list affects both copies. A deep copy (copy.deepcopy) recursively copies everything, fully independent but slower. You reach for deepcopy only when shared inner references would cause bugs.
Preparation tips
Walk in ready.
- Write a generator that streams a large file
- Implement a timing decorator with functools.wraps
- Use a context manager for resource cleanup
- Know which dunders make an object hashable
Ready for the real thing?
Run a 6-question Python mock interview, answer out loud, and get a readiness score with tips and model answers.
More intermediate interviews