Interview questionsPython
Python interview questions and answers
30 Python questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.
Junior level Python questions
1.What is the output of the following code?
javascriptimport asyncio async def compute(): await asyncio.sleep(0) return 42 async def main(): result = await compute() print(result) asyncio.run(main())- A.<coroutine object compute at 0x...>
- B.TypeError: 'coroutine' object is not callable
- C.None
- D.42
Show answer
Answer: D. 42
await compute()runs thecomputecoroutine to completion and evaluates to whatever it returns —42.resultcorrectly captures that value, andprint(result)outputs42.From the quiz Coroutines & asyncio.run
2.What is the output of the following code?
javascriptfrom collections import deque d = deque([1, 2, 3]) d.appendleft(0) d.append(4) d.popleft() print(list(d))- A.[0, 1, 2, 3, 4]
- B.[1, 2, 3, 4]
- C.[1, 2, 3]
- D.[0, 1, 2, 3]
Show answer
Answer: B. [1, 2, 3, 4]
Start:[1, 2, 3].appendleft(0)adds to the front:[0, 1, 2, 3].append(4)adds to the end:[0, 1, 2, 3, 4].popleft()removes from the front (0):[1, 2, 3, 4].From the quiz Collections Basics
3.What is the output of the following code?
javascriptclass InsufficientFundsError(Exception): def __init__(self, balance, amount): self.balance = balance self.amount = amount super().__init__(f"Cannot withdraw {amount}, balance is {balance}") try: raise InsufficientFundsError(50, 100) except InsufficientFundsError as e: print(str(e)) print(e.amount)- A.TypeError: Exception.__init__() takes 1 positional argument
- B.Cannot withdraw 100, balance is 50 then 100
- C.InsufficientFundsError then 100
- D.Cannot withdraw 100, balance is 50 then 50
Show answer
Answer: B. Cannot withdraw 100, balance is 50 then 100
Custom exceptions subclassExceptionand can define their own__init__with additional attributes alongside callingsuper().__init__(message)to set the standard exception message.str(e)returns that formatted message;e.amountaccesses the custom attribute directly,100.From the quiz Try, Except & Finally
4.What is the output of the following code?
javascriptfrom functools import reduce nums = [1, 2, 3, 4] result = reduce(lambda acc, x: acc + x, nums) print(result)- A.24
- B.TypeError: reduce expected at least 3 arguments, got 2
- C.10
- D.[1, 2, 3, 4]
Show answer
Answer: C. 10
reduce(function, iterable)appliesfunctioncumulatively, left to right:acc=1, x=2 → 3;acc=3, x=3 → 6;acc=6, x=4 → 10. The final accumulated value,10, is returned.From the quiz map, filter & reduce
5.What is the output of the following code?
javascripta = [1, 2, 3] b = [1, 2, 3] c = a print(a == b) print(a is b) print(a is c) print(a == c)- A.True, True, True, True
- B.False, False, True, True
- C.True, False, False, True
- D.True, False, True, True
Show answer
Answer: D. True, False, True, True
==compares values (via__eq__), whileiscompares object identity (whether both names point to the exact same object in memory).aandbare two separate list objects with equal contents, soa == bisTruebuta is bisFalse.c = amakescrefer to the same object asa, soa is cisTrue, and naturallya == cis alsoTrue.From the quiz Core Concepts
6.What is the output of the following code?
javascriptclass Account: def __init__(self, balance): self._balance = balance self.__pin = "1234" a = Account(100) print(a._balance) print(a.__pin)- A.100 then 1234
- B.100 then AttributeError
- C.100 then _Account__pin
- D.AttributeError then AttributeError
Show answer
Answer: B. 100 then AttributeError
A single leading underscore (_balance) is only a naming convention signaling internal use — Python enforces nothing, soa._balanceworks fine. A double leading underscore (__pin) triggers name mangling: Python internally rewrites it to_Account__pin, so accessing it asa.__pinfrom outside the class raisesAttributeError, since an attribute literally named__pinno longer exists.From the quiz Classes & Instances
7.What is the output of the following code?
javascriptimport asyncio async def slow(): await asyncio.sleep(0.1) return "slow done" async def fast(): await asyncio.sleep(0.01) return "fast done" async def main(): results = await asyncio.gather(slow(), fast()) print(results) asyncio.run(main())- A.TypeError: gather() takes at most 1 argument
- B.Unpredictable order, depending on which coroutine finishes first.
- C.['fast done', 'slow done']
- D.['slow done', 'fast done']
Show answer
Answer: D. ['slow done', 'fast done']
asyncio.gather(*coros)runs all given coroutines concurrently, but its returned results list is always ordered to match the order the coroutines were passed in, regardless of which one actually finishes first. Sinceslow()was passed first andfast()second, the results are['slow done', 'fast done'], even thoughfast()completes sooner in real time.From the quiz Coroutines & asyncio.run
8.What is the output of the following code?
javascriptmatrix = [[1, 2, 3], [4, 5, 6]] flat = [num for row in matrix for num in row if num % 2 == 0] print(flat)- A.[2, 6]
- B.[[2], [4, 6]]
- C.[2, 4, 6]
- D.[1, 3, 5]
Show answer
Answer: C. [2, 4, 6]
This nested comprehension is equivalent to: Iterating[1, 2, 3]then[4, 5, 6], keeping only even numbers:2,4,6.From the quiz Collections Basics
9.What is the output of the following code?
javascriptdef f(): try: return "from try" finally: print("finally ran") result = f() print(result)- A.from try then finally ran
- B.finally ran then from try
- C.TypeError: 'finally' block cannot coexist with 'return'
- D.finally ran only — the return in try is overridden and nothing is returned.
Show answer
Answer: B. finally ran then from try
Even thoughtryhas areturnstatement,finallystill runs before the function actually returns control to the caller."finally ran"prints during the function call, beforef()actually returns its value; only afterward isresultassigned and printed.From the quiz Try, Except & Finally
10.What is the output of the following code?
javascriptfrom functools import reduce nums = [1, 2, 3] result = reduce(lambda acc, x: acc + x, nums, 100) print(result)- A.6
- B.TypeError: reduce() takes at most 2 arguments
- C.100
- D.106
Show answer
Answer: D. 106
The third argument toreduce(function, iterable, initial)seeds the accumulators **starting value** instead of using the iterables first element. Starting withacc=100:100+1=101,101+2=103,103+3=106.From the quiz map, filter & reduce
Mid level Python questions
11.What is the output of the following code?
javascriptimport asyncio async def fails(): raise ValueError("boom") async def succeeds(): return "ok" async def main(): results = await asyncio.gather(fails(), succeeds(), return_exceptions=True) print(results) asyncio.run(main())- A.Raises ValueError: boom, uncaught, crashing the program.
- B.[None, 'ok']
- C.['ok']
- D.[ValueError('boom'), 'ok']
Show answer
Answer: D. [ValueError('boom'), 'ok']
Withreturn_exceptions=True,gather()does not raise the first exception it encounters — instead, it captures each awaitables outcome (a return value or a raised exception) and returns them all together in a single list, in the original input order. The failing coroutines exception object itself appears in the results list, alongside the successful coroutine's actual return value.From the quiz Tasks & Concurrency
12.What is the output of the following code?
javascriptd = {"a": [1]} d.setdefault("a", []).append(2) d.setdefault("b", []).append(3) print(d)- A.{'a': [1, 2], 'b': [3]}
- B.{'a': [1, 2]}
- C.KeyError
- D.{'a': [1], 'b': [3]}
Show answer
Answer: A. {'a': [1, 2], 'b': [3]}
d.setdefault("a", []):"a"already exists, sosetdefaultreturns the existing list[1](the[]default is ignored entirely), and.append(2)mutates it to[1, 2].d.setdefault("b", []):"b"does not exist, sosetdefaultinserts"b": []into the dict and returns that same new list, which.append(3)mutates to[3].From the quiz Advanced Collections
13.What is the output of the following code?
javascriptfrom contextlib import suppress with suppress(FileNotFoundError): open("does_not_exist.txt") print("continued normally")- A.TypeError: suppress() missing required argument
- B.FileNotFoundError: [Errno 2] No such file or directory: 'does_not_exist.txt'
- C.Nothing is printed — suppress also suppresses the rest of the program.
- D.continued normally
Show answer
Answer: D. continued normally
contextlib.suppress(ExceptionType)catches and discards any instance of the given exception type(s) raised inside itswithblock — a concise shortcut fortry/except: passlimited to specific exception types.open()on a nonexistent file raisesFileNotFoundError, whichsuppressswallows, so execution continues normally to the print statement.From the quiz Chaining & Context Managers
14.What is the output of the following code?
javascriptfrom itertools import permutations, combinations items = ['A', 'B', 'C'] print(len(list(permutations(items, 2)))) print(len(list(combinations(items, 2))))- A.3, 3
- B.6, 6
- C.6, 3
- D.3, 6
Show answer
Answer: C. 6, 3
permutations(items, 2)counts order-sensitive selections of 2 from 3 items:AB, BA, AC, CA, BC, CB— 6 total.combinations(items, 2)counts order-insensitive selections (ABandBAcount as the same selection):AB, AC, BC— 3 total.From the quiz itertools & partial
15.What is the output of the following code?
javascriptx = 100 squares = [x * x for x in range(5)] print(x) print(squares)- A.100, [0, 1, 4, 9, 16]
- B.4, [0, 1, 4, 9, 16]
- C.4, [0, 1, 2, 3, 4]
- D.100, [0, 1, 2, 3, 4]
Show answer
Answer: A. 100, [0, 1, 4, 9, 16]
In Python 3, list (and set/dict) comprehensions run in their own implicit scope — the loop variablexinside the comprehension does not leak into (or overwrite) the enclosing scope'sx. So the outerxstays100, whilesquarescorrectly holds[0, 1, 4, 9, 16].From the quiz Functions & Scope
16.What is the output of the following code?
javascriptfrom dataclasses import dataclass, field @dataclass class Cart: items: list = field(default_factory=list) c1 = Cart() c2 = Cart() c1.items.append("apple") print(c1.items) print(c2.items)- A.['apple'] then []
- B.['apple'] then ['apple']
- C.[] then []
- D.ValueError: mutable default <class 'list'> for field items is not allowed
Show answer
Answer: A. ['apple'] then []
field(default_factory=list)callslist()fresh for each instance created, giving everyCartits own independent list — unlike a bare mutable default value shared across instances. Soc1andc2have separate lists, and mutatingc1.itemshas no effect onc2.items.From the quiz Dataclasses & ABCs
17.What is the output of the following code?
javascriptimport asyncio counter = 0 async def increment(lock): global counter async with lock: current = counter await asyncio.sleep(0) counter = current + 1 async def main(): lock = asyncio.Lock() await asyncio.gather(*(increment(lock) for _ in range(5))) print(counter) asyncio.run(main())- A.5
- B.0
- C.Possibly less than 5, due to a race condition.
- D.TypeError: Lock() takes no arguments
Show answer
Answer: A. 5
async with lock:ensures only one coroutine at a time executes the critical section. Even thoughawait asyncio.sleep(0)inside the locked section yields control back to the event loop, the lock prevents any other coroutine from entering the critical section until the current holder releases it — so all 5 increments happen safely, one at a time, correctly summing to5.From the quiz Tasks & Concurrency
18.What is the output of the following code?
javascriptimport heapq nums = [5, 1, 8, 3] heapq.heapify(nums) heapq.heappush(nums, 0) print(nums[0]) print(heapq.heappop(nums)) print(nums[0])- A.0, 0, 1
- B.1, 1, 3
- C.0, 1, 3
- D.1, 0, 1
Show answer
Answer: A. 0, 0, 1
Afterheapify,nums[0]is guaranteed to be the smallest element — but that's before the push. Onceheappush(nums, 0)adds0, it becomes the new smallest, so the firstprint(nums[0])shows0.heappop(nums)removes and returns the current smallest element,0. After that removal, the new smallest among the remaining elements is1, so the finalprint(nums[0])shows1.From the quiz Advanced Collections
19.What is the output of the following code?
javascriptclass Named: def __init__(self, name): self.name = name def __enter__(self): print(f"enter {self.name}") return self def __exit__(self, *args): print(f"exit {self.name}") with Named("A"), Named("B"): print("inside")- A.enter A, enter B, inside, exit A, exit B
- B.enter A, enter B, inside, exit B, exit A
- C.enter A, inside, exit A, enter B, exit B
- D.enter B, enter A, inside, exit A, exit B
Show answer
Answer: B. enter A, enter B, inside, exit B, exit A
Multiple context managers in onewithstatement are entered left to right (AthenB) — same as nestingwith A(): with B():. They're exited in reverse order (BthenA) — a last acquired, first released pattern.From the quiz Chaining & Context Managers
20.What is the output of the following code?
javascriptfrom itertools import groupby data = [1, 1, 2, 2, 1, 3] grouped = {key: list(group) for key, group in groupby(data)} print(grouped)- A.KeyError
- B.{1: [1], 2: [2, 2], 3: [3]}
- C.{1: [1, 1, 1], 2: [2, 2], 3: [3]}
- D.{1: [1, 1], 2: [2, 2], 3: [3]}
Show answer
Answer: B. {1: [1], 2: [2, 2], 3: [3]}
groupby(data)(without an explicitkeyfunction) groups only consecutive equal elements — even if the same value reappears later non-consecutively, it starts a brand-new group rather than merging with an earlier one. For[1, 1, 2, 2, 1, 3], the consecutive runs are:(1, 1),(2, 2),(1,),(3,)— four separate groups, with key1appearing twice. Since the dict comprehension assigns togrouped[key]for each group in order, the later group for key1(just[1]) overwrites the earlier one ([1, 1]). Final dict:{1: [1], 2: [2, 2], 3: [3]}.From the quiz itertools & partial
Senior level Python questions
21.Which statement correctly contrasts
asyncio.gather()withasyncio.TaskGroup(Python 3.11+) regarding sibling failure behavior?- A.gather() (by default) cancels siblings on failure, while TaskGroup does not.
- B.When one task inside an async with asyncio.TaskGroup() as tg: block raises an exception, TaskGroup automatically cancels all the other still-running tasks in the group before propagating — unlike gather()'s default behavior, which leaves siblings running.
- C.TaskGroup and gather() behave identically regarding sibling cancellation on failure.
- D.TaskGroup never propagates exceptions at all — it silently logs them instead.
Show answer
Answer: B. When one task inside an async with asyncio.TaskGroup() as tg: block raises an exception, TaskGroup automatically cancels all the other still-running tasks in the group before propagating — unlike gather()'s default behavior, which leaves siblings running.
asyncio.TaskGroupimplements structured concurrency — a failure in any child task automatically cancels all its siblings before the exception propagates, ensuring no orphaned background tasks are left running after an error.From the quiz Synchronization Primitives
22.What is the output of the following code?
javascriptdata = [("apple", 2), ("banana", 1), ("cherry", 2), ("date", 1)] step1 = sorted(data, key=lambda x: x[0]) step2 = sorted(step1, key=lambda x: x[1]) print(step2)- A.[('apple', 2), ('banana', 1), ('cherry', 2), ('date', 1)]
- B.Unpredictable/undefined order among tied elements
- C.[('banana', 1), ('date', 1), ('apple', 2), ('cherry', 2)]
- D.[('date', 1), ('banana', 1), ('cherry', 2), ('apple', 2)]
Show answer
Answer: C. [('banana', 1), ('date', 1), ('apple', 2), ('cherry', 2)]
Python'ssorted()is stable — it preserves the relative order of elements that compare equal under the current key.step1sorts alphabetically:apple, banana, cherry, date.step2then sorts by the number, but because the sort is stable, elements sharing the same number retain their relative order fromstep1. Among the1s:bananaprecededdateinstep1, so that order carries through. Among the2s:appleprecededcherryinstep1, likewise preserved. Final:banana(1), date(1), apple(2), cherry(2).From the quiz Ordering & Aliasing
23.What is the output of the following code?
javascriptclass Broken: def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): raise ValueError("cleanup failed") try: with Broken(): raise RuntimeError("original error") except Exception as e: print(type(e).__name__)- A.ValueError — the exception raised inside __exit__ replaces the original exception from the with block's body.
- B.Both exceptions somehow propagate together, and type(e).__name__ raises an error trying to determine which one to report.
- C.RuntimeError — the original exception always takes priority over anything __exit__ does.
- D.TypeError: __exit__() cannot raise exceptions
Show answer
Answer: A. ValueError — the exception raised inside __exit__ replaces the original exception from the with block's body.
If__exit__itself raises a new exception, that new exception replaces whatever exception was already propagating from thewithblock's body. The originalRuntimeErroris discarded as the active exception (though still linked via__context__). The code catching the exception seesValueError, notRuntimeError.From the quiz ExitStack & Exception Groups
24.What is the output of the following code?
javascriptdef memoize(func, cache={}): def wrapper(n): if n not in cache: cache[n] = func(n) return cache[n] return wrapper call_count = 0 def slow_square(n): global call_count call_count += 1 return n * n fast_square = memoize(slow_square) fast_square(5) fast_square(5) fast_square(3) print(call_count)- A.TypeError: memoize() missing 1 required positional argument: 'cache'
- B.3
- C.2
- D.1
Show answer
Answer: C. 2
fast_square(5)(first call) isn't cached yet, soslow_squareruns, incrementingcall_countto1.fast_square(5)(second call) finds5already cached — no new call.fast_square(3)is a genuinely new argument, soslow_squareruns again, incrementingcall_countto2.From the quiz Composition & Closures
25.What is the output of the following code?
javascriptclass Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.x = 10 print(p.x) p.z = 5- A.1, then AttributeError
- B.10, then 5 is stored without issue
- C.10, then AttributeError
- D.10, then TypeError
Show answer
Answer: C. 10, then AttributeError
__slots__restricts instances to exactly the named attributes (x,y) and prevents a per-instance__dict__from being created. Reassigningp.x = 10is valid sincexis a declared slot, soprint(p.x)outputs10. Butp.z = 5tries to set an attribute not declared in__slots__, raisingAttributeError.From the quiz Advanced Patterns
26.What is the output of the following code?
javascriptclass Stack: def __class_getitem__(cls, item): return f"{cls.__name__}[{item.__name__}]" print(Stack[int])- A.TypeError: 'type' object is not subscriptable
- B.<class '__main__.Stack'>
- C.Stack[int]
- D.AttributeError
Show answer
Answer: C. Stack[int]
__class_getitem__(PEP 560) lets a class support subscript syntax (Stack[int]) at the class level, not just on instances. Python callsStack.__class_getitem__(int), which returns the formatted string"Stack[int]", andprintdisplays it.From the quiz Advanced OOP
27.Which statement correctly describes safely interacting with an asyncio event loop from a different OS thread?
- A.asyncio objects (Futures, Tasks, Queues) are fully thread-safe by default — any thread can freely call their methods directly.
- B.threading.Lock should always be used instead of asyncio.Lock when working with asyncio code, since asyncio doesn't have real concurrency anyway.
- C.It's impossible for any other thread to ever communicate with a running asyncio event loop.
- D.Calling asyncio objects (like setting a Future's result, or scheduling a callback) directly from a different OS thread is not safe — you must use thread-safe methods like loop.call_soon_threadsafe() to schedule that interaction properly onto the event loop's own thread.
Show answer
Answer: D. Calling asyncio objects (like setting a Future's result, or scheduling a callback) directly from a different OS thread is not safe — you must use thread-safe methods like loop.call_soon_threadsafe() to schedule that interaction properly onto the event loop's own thread.
asyncios core objects are designed to be used from within the event loops own thread — calling their methods directly from a different thread is unsafe.loop.call_soon_threadsafe(callback)is the correct, safe bridge for scheduling cross-thread interactions.From the quiz Synchronization Primitives
28.What is the output of the following code?
javascriptclass Fruit: def __init__(self, name): self.name = name def __eq__(self, other): return isinstance(other, Fruit) and self.name == other.name basket = [Fruit("apple"), Fruit("banana")] print(Fruit("apple") in basket) print(Fruit("apple") is basket[0])- A.True, True
- B.TypeError: Fruit.__eq__ not supported by 'in'
- C.True, False
- D.False, False
Show answer
Answer: C. True, False
Theinoperator checks membership using==(calling__eq__) against each element, notis.Fruit("apple") == basket[0]isTrue, since__eq__compares by.name, even though they're distinct object instances — soinfinds a match,True.Fruit("apple") is basket[0]checks identity, and these are genuinely two separate objects (a freshly constructed one vs. the one stored in the list), soisisFalse.From the quiz Ordering & Aliasing
29.What is the output of the following code?
javascriptfrom contextlib import ExitStack def cleanup(name): print(f"cleaning up {name}") with ExitStack() as stack: stack.callback(cleanup, "resource-1") stack.callback(cleanup, "resource-2") print("working")- A.working, cleaning up resource-2, cleaning up resource-1
- B.cleaning up resource-1, cleaning up resource-2, working
- C.TypeError: callback() missing required argument
- D.working, cleaning up resource-1, cleaning up resource-2
Show answer
Answer: A. working, cleaning up resource-2, cleaning up resource-1
stack.callback(func, *args)registers a plain function to be called automatically when theExitStacks `with` block exits. Multiple registered callbacks run in reverse registration order (LIFO), exactly like `enter_context()`-registered context managers — so `"resource-2"`s cleanup runs before"resource-1"'s.From the quiz ExitStack & Exception Groups
30.What is the output of the following code?
javascriptdef bold(func): def wrapper(): return f"<b>{func()}</b>" return wrapper def italic(func): def wrapper(): return f"<i>{func()}</i>" return wrapper @bold @italic def greet(): return "hello" print(greet())- A.<b>hello</b><i>hello</i>
- B.<i><b>hello</b></i>
- C.<b><i>hello</i></b>
- D.TypeError: greet() takes 0 positional arguments
Show answer
Answer: C. <b><i>hello</i></b>
Decorators apply bottom-up (closest to the function first):@italicwrapsgreetfirst, producing an italic-wrapping function; then@boldwraps that result. Callinggreet()(nowbold's wrapper) computes the italic-wrapped inner result (<i>hello</i>) first, then wraps that in bold tags:<b><i>hello</i></b>.From the quiz Composition & Closures
Practise 650+ more Python questions
Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.