Question Bank
Python Language Trivia
Difficulty: Medium
Mid-tier Python gotchas: mutable default arguments, the GIL, method resolution order, and `is` vs `==`. Predict each snippet's output.
Python Language Trivia
Mid-tier Python gotchas: mutable default arguments, the GIL, method resolution order, and `is` vs `==`. Predict each snippet's output.
926 views
14
Predict the output of two consecutive calls. Explain the mutable-default-argument trap and the idiomatic fix.
Examples
Example 1:
Input: def append_to(value, target=[]); call append_to(1) then append_to(2)
Output (buggy version): [1], then [1, 2] (shared list)
Output (fixed version with target=None sentinel): [1], then [2]
Explanation: Default argument values are evaluated once at function definition time, not on each call, so target=[] is a single list object shared across all callers. The idiomatic fix uses None as sentinel and allocates inside the body.What is the Global Interpreter Lock, and why does CPU-bound threading rarely scale on CPython while I/O-bound threading usually does? Name one workaround for each case.
What does D().who() print? Trace Python's method resolution order (MRO) using D.__mro__.
Examples
Example 1:
Input: classes A, B(A), C(A), D(B, C); print D().who() and D.__mro__
Output: 'B'; ['D', 'B', 'C', 'A', 'object']
Explanation: Python uses C3 linearization. For D(B, C), C3 yields D -> B -> C -> A -> object, so D().who() resolves to B.who. C3 guarantees a class precedes its bases and respects the order parents are listed.Predict each line. Explain why a is b differs from a == b, and what is actually compares.
Examples
Example 1:
Input: a = b = 256; c = d = 257; e = [1, 2], f = [1, 2]; print (a is b, a == b), (c is d, c == d), (e is f, e == f)
Output: (True, True); implementation-dependent for c is d but c == d is True; (False, True)
Explanation: is checks object identity (id()); == checks value equality. CPython interns integers in [-5, 256], so a is b is True. Outside that range, identity depends on the compilation context. Two equal lists are always different objects.Write a @timeit decorator that prints elapsed time and returns the wrapped function's value unchanged. Use functools.wraps and explain why.
Examples
Example 1:
Input: decorate work(n) = sum(range(n)) with @timeit; call work(10_000)
Output: prints 'work took 0.000xxxs' and returns 49995000
Explanation: Use functools.wraps to copy __name__, __doc__, __wrapped__, __qualname__ onto the wrapper, otherwise help / signature / framework introspection reports the wrapper's metadata. Time with time.perf_counter (monotonic), not time.time.