Python Interview Mock sample questions with answers
10 questions from the Python Interview Mock practice bank, spread across its domains. Pick your answer, then open the explanation to see why each option is right or wrong.
- Question 1Language Core
What does this print?
a = [2, 4, 6, 7] for x in a: if x % 2 == 0: a.remove(x) print(a)- A
[7] - B
[4, 7] - C
It raises
RuntimeError: list changed size during iteration - D
[2, 4, 6, 7]
Show the answer and explanation
Answer: B
A
forloop over a list walks an index. Step 1: index 0 is 2, which is removed, giving[4, 6, 7]. Step 2: index 1 is now 6, which is removed, giving[4, 7]. Step 3: index 2 is past the end, so the loop stops. Build a new list instead:a = [x for x in a if x % 2], or iterate over a copy (for x in a[:]).Why the other options are wrong
A. That assumes every even number is visited, but removing items shifts the rest under the loop.
C. Lists do not detect modification during iteration; only dicts and sets raise this error.
D.
removedoes change the list: 2 and 6 are removed.
- A
- Question 2Ecosystem and Practice
This decorator is typed loosely. What type does mypy reveal for
sub, and is the bad call reported?from typing import Any, Callable def loose(fn: Callable[..., Any]) -> Callable[..., Any]: return fn @loose def sub(x: int, y: int) -> int: return x - y reveal_type(sub) sub("a", 1)- A
def (*Any, **Any) -> Any, and the call is not reported - B
def (x: int, y: int) -> int, and the call is reported - C
Callable[..., int], and the call is reported - D
Any, and mypy reports thatsubis untyped
Show the answer and explanation
Answer: A
The return annotation
Callable[..., Any]is all mypy knows about the decorated name, so it revealsdef (*Any, **Any) -> Anyand accepts any arguments. That is how a careless decorator silently switches off checking for every function it touches. Typing it withParamSpecandTypeVarpreserves the signature.Why the other options are wrong
B. mypy uses the decorator's declared return type, not the original function's.
C. The return type is
Anyas well, and...accepts any arguments.D. It reveals a callable type, and no error is emitted.
- A
- Question 3Objects and Protocols
Given
r = range(3), the expressionlist(r) == list(r)isTrue.- A
True
- B
False
Show the answer and explanation
Answer: A
rangeobjects are immutable sequences that support indexing,len()and repeated iteration. Only the iterator you get fromiter(r)is single-pass. Contrast withmap,zipand generators, which are exhausted after onelist().Why the other options are wrong
B. That would happen with an iterator like
iter(range(3)), not a range object.
- A
- Question 4Concurrency and Performance
A billing service switches from
floattodecimal.Decimal. Additions get roughly 3× slower in a micro-benchmark on CPython 3.13. Which reasoning is correct?- A
Decimal is software arithmetic; worth it for money, which needs exact decimal results
- B
Decimal is written in pure Python, so moving the service to PyPy will remove the gap
- C
The slowdown proves floats are exact enough, so Decimal is only needed above 2**53
- D
Decimal is slow only because each operation recreates the context; caching it removes the cost
Show the answer and explanation
Answer: A
A float addition is one CPU instruction on IEEE 754 doubles. A Decimal addition goes through libmpdec's software arithmetic plus object allocation. Measured on 3.13 it was about 3× slower per add. For money the exactness wins; storing integer cents is the other fast, exact option.
Why the other options are wrong
B. CPython uses the C implementation (_decimal/libmpdec); the cost is software arithmetic, not Python.
C. Floats can't represent 0.1 exactly at any magnitude; that's the reason to use Decimal for money.
D. The context is thread-local and reused; the cost is the arithmetic itself.
- A
- Question 5Language Core
What does this print?
class Order: @property def total(self): return (1).discount # a typo: ints have no .discount def __getattr__(self, name): return f'<missing {name}>' print(Order().total)- A
It raises
AttributeError: 'int' object has no attribute 'discount' - B
<missing discount> - C
<missing total> - D
None, because the property returns nothing
Show the answer and explanation
Answer: C
__getattr__runs whenever normal attribute lookup raises AttributeError, and that includes an AttributeError raised inside a property's getter. The real bug (the typo insidetotal) is masked by the fallback. Keep__getattr__narrow, or re-raise unknown names, to avoid hiding errors like this.Why the other options are wrong
A. That error is raised, but an AttributeError from a property triggers the
__getattr__fallback.B.
__getattr__is called on the Order instance, so it receives the Order's attribute name.D. The property doesn't return; it raises before reaching any return value.
- A
- Question 6Ecosystem and Practice
What happens when this test class runs?
import unittest class TestDB(unittest.TestCase): def setUpClass(cls): cls.db = connect() def test_query(self): self.assertTrue(self.db.ok)- A
It works: unittest calls
setUpClassonce with the class - B
A
TypeErrorfor the missingcls; it needs@classmethod - C
unittest calls it before every test, like
setUp - D
It is silently skipped, and the test fails with
AttributeErroronself.db
Show the answer and explanation
Answer: B
setUpClassandtearDownClassrun once per test class and must be declared with@classmethod. unittest invokesTestDB.setUpClass()with no arguments, so a plain function raisesTypeError: TestDB.setUpClass() missing 1 required positional argument: 'cls'. That is reported as an error, and none of the class's tests run. Verified on Python 3.13.Why the other options are wrong
A. unittest calls it on the class, so without
@classmethodtheclsargument is never filled.C.
setUpruns per test;setUpClassruns once per class and must be a classmethod.D. It isn't skipped: calling it raises a
TypeError, reported as a class-level error.
- A
- Question 7Objects and Protocols
What does this print?
def find(xs, target): for i, v in enumerate(xs): if v == target: print('found', i) break else: print('missing') find([1, 2, 3], 2) find([1, 2, 3], 9) find([], 1)- A
found 1,missing, and nothing for the empty list - B
found 1,missing,missing - C
found 1,missing,missing,missing - D
found 1 missing,missing,missing
Show the answer and explanation
Answer: B
A loop's
elseclause runs when the loop terminates normally, meaning it ran out of items, including when there were none, and is skipped when the loop exits viabreak. That makes it a natural search-failed branch: the first call breaks, so it prints onlyfound 1, while the other two calls fall through tomissing. Verified on Python 3.13.Why the other options are wrong
A. The
elseruns whenever the loop ends withoutbreak, including after zero iterations.C.
elseis skipped whenbreakruns, so the first call prints only once.D. After
break, theelseblock is skipped entirely.
- A
- Question 8Concurrency and Performance
On CPython 3.12 or later,
sum([0.1] * 10) == 1.0evaluates toTrue, even though adding 0.1 ten times in a plainforloop gives0.9999999999999999.- A
True
- B
False
Show the answer and explanation
Answer: A
Python 3.12 changed
sum()to use a compensated (Neumaier-style) algorithm for floats, sosum([0.1] * 10)is exactly 1.0. A manualt += 0.1loop still accumulates rounding error.math.fsumhas always been exact to within one rounding and remains the tool when correctness matters on any version.Why the other options are wrong
B. This was true before 3.12; newer sum() tracks the lost low-order bits as it adds.
- A
- Question 9Language Core
What happens when this module is imported?
NOT_FOUND = 404 def check(code): match code: case NOT_FOUND: return 'not found' case _: return 'other'- A
It imports fine, and
check(200)returns'other' - B
SyntaxError: the name captureNOT_FOUNDmakes the remaining patterns unreachable - C
It imports fine, but
check(200)raisesNameErrorforNOT_FOUND - D
It imports fine, and
check(404)returns'not found'whilecheck(200)returns'other'
Show the answer and explanation
Answer: B
In
match, a bare name likeNOT_FOUNDis a capture pattern: it matches anything and binds the subject to that name. Because it can never fail, a latercase _:is unreachable, and CPython raisesSyntaxError: name capture 'NOT_FOUND' makes remaining patterns unreachableat compile time. To compare against a constant, use a dotted name (HTTPStatus.NOT_FOUND,codes.NOT_FOUND) or a guard (case x if x == NOT_FOUND). Verified on Python 3.13.Why the other options are wrong
A. A bare name in a case is a capture pattern, not a comparison with the constant.
C. The pattern binds
NOT_FOUNDas a new local rather than reading the global.D. That needs a value pattern such as a dotted name; a bare name captures.
- A
- Question 10Ecosystem and Practice
What does
load()return?def load(): try: raise FileNotFoundError('cfg') except OSError: return 'OSError' except FileNotFoundError: return 'FNF'- A
'OSError' - B
'FNF' - C
It raises SyntaxError for an unreachable clause
- D
It returns both, as a tuple
Show the answer and explanation
Answer: A
Except clauses are tested top to bottom, and the first matching one wins.
FileNotFoundErroris a subclass ofOSError, so the first clause matches and the more specific clause below it can never run. Put specific exceptions before their parents (linters flag this).Why the other options are wrong
B. Python does not look for the most specific clause; it takes the first match.
C. Python accepts the code; only linters warn about it.
D. Only one except clause ever runs for a given exception.
- A
Practise all 485 PY questions
Start with the free 15-question diagnostic. It shows where to focus, and your results carry over if you sign up.