Learn Python — every question, every answer
All 125 questions across 5 levels with code samples, accepted answers, and detailed explanations. Free, no signup, fully indexed.
A complete reference for Python: from basic data types and control flow through dataclasses, decorators, and contextlib, to asyncio, FastAPI, and Pydantic. Each entry shows the runnable code, the correct answer, and the rule that makes it correct.
python-basic · Basics · 25 questions
pb1What does this code print?
x = 7
y = 2
print(x // y)- A3.5
- B3✓ Correct answer
- C4
- D3.0
Why: The // operator performs integer floor division, returning 3 when both operands are ints.
pb2Which identifier is NOT valid in Python?
- A_value
- Bmy_var2
- C2nd_place✓ Correct answer
- DCamelCase
Why: Identifiers cannot start with a digit; they must begin with a letter or underscore.
pb3What type is printed?
print(type(3 / 2))- A<class 'int'>
- B<class 'float'>✓ Correct answer
- C<class 'number'>
- D<class 'double'>
Why: The / operator always returns a float in Python 3, even with integer operands.
pb4What does this code print?
s = " Hello "
print(s.strip().upper())- A HELLO
- BHELLO✓ Correct answer
- CHello
- D Hello
Why: .strip() removes surrounding whitespace, then .upper() converts the result to uppercase.
pb5What does this slice print?
s = "python"
print(s[1:4])- Apyt
- Byth✓ Correct answer
- Cytho
- Dthon
Why: Slicing s[1:4] takes indices 1, 2, 3 — the stop index is exclusive.
pb6What does this f-string print?
name = "Ada"
print(f"Hi, {name}!")- AHi, {name}!
- BHi, Ada!✓ Correct answer
- CHi, "Ada"!
- DSyntaxError
Why: F-strings interpolate the value of expressions in braces into the string.
pb7What does this code print?
xs = [1, 2]
xs.append([3, 4])
print(len(xs))- A2
- B3✓ Correct answer
- C4
- DTypeError
Why: append adds a single element (the inner list) — length becomes 3, not 4.
pb8What does this code print?
xs = [1, 2, 3]
xs.extend([4, 5])
print(xs)- A[1, 2, 3, [4, 5]]
- B[1, 2, 3, 4, 5]✓ Correct answer
- C[4, 5, 1, 2, 3]
- D[1, 2, 3]
Why: extend iterates the argument and appends each element individually to the list.
pb9What happens when this code runs?
t = (1, 2, 3)
t[0] = 9
print(t)- APrints (9, 2, 3)
- BPrints (1, 2, 3)
- CTypeError✓ Correct answer
- DIndexError
Why: Tuples are immutable; assigning to an index raises TypeError.
pb10What does this code print?
d = {"a": 1, "b": 2}
print(d.get("c", 0))- ANone
- BKeyError
- C0✓ Correct answer
- D1
Why: dict.get(key, default) returns the default value when the key is not present.
pb11What does the in operator check on a dict?
d = {"x": 1}
print("x" in d)- AMembership of values
- BMembership of keys✓ Correct answer
- CMembership of items
- DAlways False
Why: For dicts, the in operator tests whether a key exists, not values.
pb12What does this code print?
s = {1, 2, 2, 3, 3, 3}
print(len(s))- A6
- B3✓ Correct answer
- C2
- D1
Why: Sets store only unique elements, so duplicates are removed leaving {1, 2, 3}.
pb13What does this code print?
vals = [0, "", None, [], "x"]
truthy = [v for v in vals if v]
print(len(truthy))- A5
- B4
- C1✓ Correct answer
- D0
Why: 0, "", None, and [] are all falsy; only "x" survives the filter.
pb14What does this code print?
x = 10
if x > 20:
print("A")
elif x > 5:
print("B")
else:
print("C")- AA
- BB✓ Correct answer
- CC
- DBC
Why: Only the first matching branch executes; 10 > 5 is true so "B" prints.
pb15What does this code print?
total = 0
for i in range(1, 5):
total += i
print(total)- A15
- B10✓ Correct answer
- C6
- D4
Why: range(1, 5) yields 1, 2, 3, 4 (stop is exclusive); their sum is 10.
pb16What is the first line printed?
names = ["a", "b", "c"]
for i, n in enumerate(names):
print(i, n)- A1 a
- B0 a✓ Correct answer
- Ca 0
- D0 "a"
Why: enumerate yields (index, value) starting at 0 by default.
pb17What does this code print?
a = [1, 2, 3]
b = ["x", "y"]
print(list(zip(a, b)))- A[(1, 'x'), (2, 'y'), (3, None)]
- B[(1, 'x'), (2, 'y')]✓ Correct answer
- C[1, 'x', 2, 'y', 3]
- DError
Why: zip stops at the shortest iterable, so the third element of a is dropped.
pb18What does this comprehension print?
squares = [x*x for x in range(4)]
print(squares)- A[1, 4, 9, 16]
- B[0, 1, 4, 9]✓ Correct answer
- C[0, 1, 2, 3]
- D[1, 2, 4, 8]
Why: range(4) yields 0, 1, 2, 3; squaring each gives [0, 1, 4, 9].
pb19What does this code print?
def greet(name, greeting="Hi"):
return f"{greeting}, {name}"
print(greet("Sam"))- AHi, Sam✓ Correct answer
- BSam, Hi
- CTypeError
- DHi, name
Why: Default arguments are used when the caller omits them; greeting defaults to "Hi".
pb20What does this code print?
def total(*args, **kwargs):
return sum(args) + sum(kwargs.values())
print(total(1, 2, x=3, y=4))- A3
- B7
- C10✓ Correct answer
- DTypeError
Why: *args collects (1, 2) and **kwargs collects {x:3, y:4}; sums give 3 + 7 = 10.
pb21What does this code print?
def f():
pass
print(type(f()).__name__)- ANone
- BNoneType✓ Correct answer
- Cfunction
- Dvoid
Why: A function without return yields None, whose class name is NoneType.
pb22What does this code print?
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b, a is b)- ATrue True
- BTrue False✓ Correct answer
- CFalse True
- DFalse False
Why: == compares values (equal); is checks identity — they are different objects.
pb23What does this code print?
print(isinstance(True, int))- ATrue✓ Correct answer
- BFalse
- CTypeError
- DNone
Why: In Python, bool is a subclass of int, so isinstance(True, int) is True.
pb24What does this code print?
try:
x = int("abc")
except ValueError:
x = -1
print(x)- A0
- B-1✓ Correct answer
- Cabc
- DValueError
Why: int("abc") raises ValueError, which is caught and sets x to -1.
pb25What does this code print?
import math
print(math.sqrt(16))- A4
- B4.0✓ Correct answer
- C16
- DImportError
Why: math.sqrt always returns a float, so sqrt(16) prints 4.0, not 4.
python-medium · Intermediate · 25 questions
pm1What does this print?
class Dog:
species = 'canine'
def __init__(self, name):
self.name = name
a = Dog('Rex')
Dog.species = 'wolf'
print(a.species)- Acanine
- Bwolf✓ Correct answer
- CRex
- DAttributeError
Why: species is a class attribute; changing it on the class is reflected on instances without their own override.
pm2What does this print?
class A:
def hi(self): return 'A'
class B(A):
def hi(self): return 'B' + super().hi()
print(B().hi())- AB
- BA
- CBA✓ Correct answer
- DAB
Why: B.hi returns "B" concatenated with super().hi() which calls A.hi returning "A", yielding "BA".
pm3What does this print?
class Temp:
def __init__(self, c):
self._c = c
@property
def f(self):
return self._c * 9/5 + 32
t = Temp(100)
print(t.f)- A212.0✓ Correct answer
- B212
- C<property>
- DTypeError
Why: @property makes f accessible without parentheses; 100*9/5+32 equals 212.0 due to true division.
pm4What does this print?
class Math:
@staticmethod
def add(a, b): return a + b
@classmethod
def name(cls): return cls.__name__
print(Math.add(2, 3), Math.name())- A5 Math✓ Correct answer
- B5 cls
- CTypeError
- D23 Math
Why: @staticmethod takes no implicit args; @classmethod receives cls bound to the class itself.
pm5What does this print?
def shout(fn):
def wrap(*a, **k):
return fn(*a, **k).upper()
return wrap
@shout
def greet(n): return f'hi {n}'
print(greet('ann'))- AHI ANN✓ Correct answer
- Bhi ann
- CHI ann
- DTypeError
Why: The decorator wraps greet; result "hi ann" is uppercased to "HI ANN" before return.
pm6What is the output order?
class Open:
def __enter__(self):
print('in'); return self
def __exit__(self, *a):
print('out')
with Open():
print('mid')- Ain, mid, out✓ Correct answer
- Bmid, in, out
- Cin, out, mid
- Dout, mid, in
Why: __enter__ runs first, then the with body, then __exit__ when the block ends.
pm7What does this print?
def gen():
yield 1
yield 2
yield 3
g = gen()
print(next(g), next(g))- A1 2✓ Correct answer
- B1 1
- C2 3
- D1 2 3
Why: Each next() advances the generator to the next yield, returning 1 then 2.
pm8What does this print?
try:
raise ValueError('a')
except ValueError:
print('v')
else:
print('e')
finally:
print('f')- Av then f✓ Correct answer
- Bv then e then f
- Ce then f
- Donly f
Why: else runs only when no exception was raised; finally always runs after handling.
pm9What does this print?
class C:
def __init__(self): self.i = 0
def __iter__(self): return self
def __next__(self):
if self.i >= 2: raise StopIteration
self.i += 1
return self.i
print(list(C()))- A[1, 2]✓ Correct answer
- B[0, 1]
- C[1, 2, 3]
- D[]
Why: list() iterates until StopIteration; values 1 and 2 are returned before i reaches 2.
pm10What does this print?
nums = [1, 2, 3, 4, 5]
print([x*x for x in nums if x % 2])- A[1, 9, 25]✓ Correct answer
- B[1, 4, 9, 16, 25]
- C[4, 16]
- D[1, 3, 5]
Why: The comprehension keeps odd numbers and squares them: 1, 9, 25.
pm11What does this print?
nums = [1, 2, 3, 4]
print(list(filter(lambda x: x > 2, nums)))- A[3, 4]✓ Correct answer
- B[1, 2]
- C[2, 3, 4]
- D[True, True]
Why: filter keeps elements where the lambda returns truthy; only 3 and 4 exceed 2.
pm12What does this print?
from functools import partial
def power(base, exp): return base ** exp
square = partial(power, exp=2)
print(square(5))- A25✓ Correct answer
- B10
- C32
- DTypeError
Why: partial fixes exp=2; calling square(5) computes 5**2 which is 25.
pm13What does this print?
from pathlib import Path
p = Path('/tmp/data.txt')
print(p.suffix, p.stem)- A.txt data✓ Correct answer
- Btxt data
- C.txt /tmp/data
- Ddata .txt
Why: Path.suffix includes the dot (".txt"); Path.stem is the filename without suffix ("data").
pm14What does this print?
from collections import Counter
print(Counter('mississippi').most_common(2))- A[('i', 4), ('s', 4)]✓ Correct answer
- B[('i', 4), ('m', 1)]
- C[('s', 4), ('i', 4)]
- D[('p', 2), ('m', 1)]
Why: "mississippi" has four i's and four s's; most_common(2) returns them top-first.
pm15What is the first line printed?
for i, v in enumerate(['a', 'b', 'c'], start=10):
print(i, v)- A10 a✓ Correct answer
- B0 a
- C1 a
- D10 c
Why: enumerate(start=10) begins indexing at 10, so the first pair is (10, "a").
pm16What does this print?
def classify(x):
match x:
case 0: return 'zero'
case int(): return 'int'
case _: return 'other'
print(classify(5))- Aint✓ Correct answer
- Bzero
- Cother
- DSyntaxError
Why: 5 is not 0 but matches int(), so classify returns "int" before the wildcard.
pm17What does this print?
pi = 3.14159
print(f'{pi:.2f}')- A3.14✓ Correct answer
- B3.142
- C3.14159
- D3.1
Why: The .2f format specifier rounds the float to two decimal places.
pm18What does this print?
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
b[0].append(9)
print(a)- A[[1, 2, 9], [3, 4]]✓ Correct answer
- B[[1, 2], [3, 4]]
- C[[1, 2], [3, 4, 9]]
- D[[1, 2, 9], [3, 4, 9]]
Why: copy.copy is shallow; inner lists are shared, so modifying b[0] also affects a[0].
pm19What does this print?
print('a,b,c,d'.split(',', maxsplit=2))- A['a', 'b', 'c,d']✓ Correct answer
- B['a', 'b', 'c', 'd']
- C['a,b', 'c', 'd']
- D['a', 'b,c,d']
Why: maxsplit=2 produces three pieces; the remainder "c,d" stays joined as one element.
pm20What does this print?
a = {'x': 1, 'y': 2}
b = {'y': 9, 'z': 3}
print(a | b)- A{'x': 1, 'y': 9, 'z': 3}✓ Correct answer
- B{'x': 1, 'y': 2, 'z': 3}
- C{'y': 9, 'z': 3}
- DTypeError
Why: The | operator merges dicts; on key conflicts the right operand wins, so y becomes 9.
pm21What does this print?
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
print(sorted(pairs, key=lambda p: p[1]))- A[(3, 'a'), (1, 'b'), (2, 'c')]✓ Correct answer
- B[(1, 'b'), (2, 'c'), (3, 'a')]
- C[(1, 'b'), (3, 'a'), (2, 'c')]
- D[(2, 'c'), (1, 'b'), (3, 'a')]
Why: The key extracts each tuple's second element, sorting alphabetically by letter.
pm22What is the second line printed?
def add(x, items=[]):
items.append(x)
return items
print(add(1))
print(add(2))- A[1, 2]✓ Correct answer
- B[2]
- C[1]
- D[2, 1]
Why: Mutable default arguments are shared across calls; the same list accumulates 1 then 2.
pm23What does this print?
from collections import defaultdict
d = defaultdict(int)
for c in 'abca':
d[c] += 1
print(dict(d))- A{'a': 2, 'b': 1, 'c': 1}✓ Correct answer
- B{'a': 1, 'b': 1, 'c': 1}
- CKeyError
- D{'a': 2}
Why: defaultdict(int) creates missing keys with value 0; counting "abca" gives a=2, b=1, c=1.
pm24What does this print?
from functools import reduce
print(reduce(lambda a, b: a + b, [1, 2, 3, 4], 10))- A20✓ Correct answer
- B10
- C24
- D14
Why: reduce starts with initializer 10 and adds 1+2+3+4=10, totaling 20.
pm25What does this print?
from collections import deque
d = deque([1, 2, 3])
d.appendleft(0)
d.append(4)
print(list(d))- A[0, 1, 2, 3, 4]✓ Correct answer
- B[1, 2, 3, 0, 4]
- C[4, 0, 1, 2, 3]
- D[0, 4, 1, 2, 3]
Why: appendleft prepends 0; append adds 4 at the end, giving [0, 1, 2, 3, 4].
python-advanced · Advanced · 25 questions
pa1Does this type-check and what does it print?
from typing import Protocol
class Greeter(Protocol):
def hi(self) -> str: ...
class En:
def hi(self) -> str:
return 'hello'
def shout(g: Greeter) -> str:
return g.hi().upper()
print(shout(En()))- ANo, En does not inherit Greeter
- BYes, prints HELLO✓ Correct answer
- CYes, prints hello
- DTypeError at runtime
Why: Protocol uses structural typing: any class with matching methods satisfies it without explicit inheritance.
pa2What happens with this frozen dataclass?
from dataclasses import dataclass, field
@dataclass(frozen=True)
class P:
name: str
tags: list[str] = field(default_factory=list)
p = P('a')
p.tags.append('x')
print(p.tags)- AFrozenInstanceError on append
- BPrints []
- CPrints ['x']✓ Correct answer
- DTypeError at construction
Why: frozen=True blocks attribute reassignment, but mutable objects referenced by attributes can still be mutated in place.
pa3What does fmt(True) print?
from functools import singledispatch
@singledispatch
def fmt(x): return f'obj:{x}'
@fmt.register
def _(x: int): return f'int:{x}'
@fmt.register
def _(x: list): return f'list:{x}'
print(fmt(True))- Aobj:True
- Bint:True✓ Correct answer
- Cbool:True
- DTypeError
Why: bool is a subclass of int, so singledispatch resolves True to the int implementation via MRO.
pa4What does Python's GIL guarantee?
- AParallel CPU execution of threads
- BOnly one thread executes Python bytecode at a time✓ Correct answer
- CThread-safe user code
- DFaster I/O than asyncio
Why: The GIL serializes Python bytecode execution to one thread at a time, preventing CPU-bound parallelism but not making user code thread-safe.
pa5What is printed?
from itertools import accumulate
import operator
nums = [1, 2, 3, 4]
print(list(accumulate(nums, operator.mul)))- A[1, 2, 6, 24]✓ Correct answer
- B[1, 3, 6, 10]
- C[24]
- D[1, 2, 3, 4]
Why: accumulate yields running results: 1, 1*2, 1*2*3, 1*2*3*4 using the supplied multiplication operator.
pa6What happens?
class C:
__slots__ = ('x',)
c = C()
c.x = 1
c.y = 2
print(c.x, c.y)- APrints 1 2
- BAttributeError on c.y = 2✓ Correct answer
- CTypeError at class definition
- DPrints 1 None
Why: __slots__ disables the per-instance __dict__, so assigning attributes not listed in slots raises AttributeError.
pa7Is this valid and what prints?
from typing import TypedDict, NotRequired
class User(TypedDict):
name: str
age: NotRequired[int]
u: User = {'name': 'Ada'}
print(u.get('age', 0))- AType error: age missing
- BValid, prints 0✓ Correct answer
- CValid, prints None
- DRuntime KeyError
Why: NotRequired marks a TypedDict key as optional, so omitting age is valid; .get returns the default 0.
pa8Why use ExitStack here?
from contextlib import ExitStack
def open_all(paths):
with ExitStack() as stack:
files = [stack.enter_context(open(p)) for p in paths]
return [f.read() for f in files]
print(type(open_all([])).__name__)- ATo open files in parallel
- BTo manage a dynamic number of context managers✓ Correct answer
- CTo suppress IOError
- DIt replaces try/except
Why: ExitStack lets you enter an unknown number of context managers at runtime and guarantees they all get exited correctly.
pa9What does print output?
class Desc:
def __set_name__(self, owner, name):
self.name = '_' + name
def __get__(self, obj, t=None):
return getattr(obj, self.name, 0)
def __set__(self, obj, v):
setattr(obj, self.name, v * 2)
class A:
x = Desc()
a = A(); a.x = 5
print(a.x)- A5
- B10✓ Correct answer
- C0
- DAttributeError
Why: The descriptor's __set__ stores 5*2 in _x; __get__ retrieves _x, returning 10.
pa10What is printed?
from enum import StrEnum, auto
class Color(StrEnum):
RED = auto()
BLUE = auto()
print(Color.RED == 'red', Color.RED.value)- AFalse 1
- BTrue red✓ Correct answer
- CTrue RED
- DFalse red
Why: StrEnum.auto() generates the lowercased member name as value, and StrEnum members compare equal to their string value.
pa11What does itertools.groupby produce?
from itertools import groupby
data = [1, 1, 2, 2, 1, 1]
print([(k, list(g)) for k, g in groupby(data)])- A[(1,[1,1,1,1]),(2,[2,2])]
- B[(1,[1,1]),(2,[2,2]),(1,[1,1])]✓ Correct answer
- C[(1,4),(2,2)]
- D[(1,[1,1,1,1,1,1])]
Why: groupby groups only consecutive equal elements, so non-adjacent runs of the same key form separate groups.
pa12What is printed?
import weakref
class Node: pass
n = Node()
r = weakref.ref(n)
print(r() is n)
del n
print(r())- ATrue then None✓ Correct answer
- BTrue then <Node object>
- CFalse then None
- DReferenceError
Why: A weakref does not keep the referent alive; once the strong reference is deleted, calling the weakref returns None.
pa13What is the output?
from typing import TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, x: T) -> None:
self.x = x
def get(self) -> T:
return self.x
b: Box[int] = Box(3)
print(b.get() + 1)- A4✓ Correct answer
- B3
- CTypeError
- DBox[int]
Why: Generic[T] enables parametric typing; at runtime types are erased and the integer 3 + 1 evaluates to 4.
pa14Which statement about pickle vs json is TRUE?
- Ajson can serialize arbitrary Python objects
- Bpickle is safe to load from untrusted sources
- Cpickle can execute arbitrary code on load✓ Correct answer
- Djson preserves tuple vs list distinction
Why: pickle.load can execute arbitrary code via crafted payloads, so never unpickle untrusted data; json is text-only and safe.
pa15How many times is "compute" printed?
from functools import cached_property
class C:
@cached_property
def v(self):
print('compute')
return 42
c = C()
print(c.v); print(c.v)- A0
- B1✓ Correct answer
- C2
- DError: needs __slots__
Why: cached_property computes once per instance and stores the result in the instance __dict__, so subsequent accesses skip recomputation.
pa16What does this print?
ba = bytearray(b'hello')
mv = memoryview(ba)
mv[0] = ord('H')
print(ba)- Abytearray(b'hello')
- Bbytearray(b'Hello')✓ Correct answer
- CTypeError: bytes immutable
- DBufferError
Why: memoryview shares the underlying buffer of bytearray (mutable), so writing through it modifies the original in place.
pa17What does re.findall return?
import re
text = 'a1 b22 c333'
print(re.findall(r'\d+', text))- A['1', '22', '333']✓ Correct answer
- Ban iterator of Match objects
- C['a1', 'b22', 'c333']
- D[1, 22, 333]
Why: findall returns a list of matched strings, while finditer returns an iterator of Match objects with positions and groups.
pa18What does assert_never do here?
from typing import Literal, assert_never
def area(shape: Literal['sq', 'tr'], v: float) -> float:
match shape:
case 'sq': return v * v
case 'tr': return v * v / 2
case _: assert_never(shape)
print(area('sq', 3))- AAlways raises at runtime
- BStatic exhaustiveness check; type error if cases incomplete✓ Correct answer
- CSuppresses warnings
- DAsserts shape is None
Why: assert_never tells the type checker the branch is unreachable; if a Literal case is forgotten, the checker reports a type error.
pa19Best choice for CPU-bound parallelism in CPython?
- Athreading
- Basyncio
- Cmultiprocessing✓ Correct answer
- Dconcurrent.futures.ThreadPoolExecutor
Why: multiprocessing spawns separate processes with their own GIL/interpreter, achieving real CPU parallelism that threads/asyncio cannot.
pa20What is printed?
class Meta(type):
def __new__(mcs, name, bases, ns):
ns['greeting'] = 'hi'
return super().__new__(mcs, name, bases, ns)
class A(metaclass=Meta):
pass
print(A.greeting)- Ahi✓ Correct answer
- BAttributeError
- CNone
- DTypeError: metaclass conflict
Why: The metaclass injects greeting into the class namespace before the class is created, so A.greeting equals "hi".
pa21What is r?
match point := (1, 0):
case (0, 0): r = 'origin'
case (x, 0): r = f'x-axis:{x}'
case (0, y): r = f'y-axis:{y}'
case _: r = 'other'
print(r)- Aorigin
- Bx-axis:1✓ Correct answer
- Cy-axis:0
- Dother
Why: Patterns are tried top-down; (1,0) does not match (0,0), then matches (x,0) binding x=1, producing "x-axis:1".
pa22Why use ContextVar instead of a global?
from contextvars import ContextVar
import asyncio
user: ContextVar[str] = ContextVar('user')
async def who():
return user.get()
async def main():
user.set('ada')
print(await who())
asyncio.run(main())- AFaster than globals
- BPer-task/coroutine isolation without explicit passing✓ Correct answer
- CThread-safe lock substitute
- DRequired by asyncio.run
Why: ContextVar values are bound to the current context (task), so concurrent tasks see independent values without threading them through arguments.
pa23What does ParamSpec preserve?
from typing import ParamSpec, TypeVar, Callable
from functools import wraps
P = ParamSpec('P')
R = TypeVar('R')
def log(f: Callable[P, R]) -> Callable[P, R]:
@wraps(f)
def w(*a: P.args, **k: P.kwargs) -> R:
return f(*a, **k)
return w- AOnly the return type
- BThe full parameter signature of the wrapped callable✓ Correct answer
- CRuntime performance
- DThe function name
Why: ParamSpec captures both positional and keyword parameters of a callable so decorators can forward them with full type fidelity.
pa24What does this print?
from itertools import islice, count
print(list(islice(count(10, 2), 2, 5)))- A[14, 16, 18]✓ Correct answer
- B[10, 12, 14]
- C[12, 14, 16, 18]
- D[2, 3, 4]
Why: count(10,2) yields 10,12,14,16,18,...; islice with start=2 stop=5 takes indices 2,3,4 → 14,16,18.
pa25Why annotate add's return as Self instead of "Builder"?
from typing import Self
class Builder:
def __init__(self) -> None:
self.parts: list[str] = []
def add(self, p: str) -> Self:
self.parts.append(p)
return self
class SubBuilder(Builder): pass- ASelf is faster at runtime
- BSelf preserves the subclass type for fluent chaining✓ Correct answer
- CSelf forbids subclassing
- DThey are equivalent
Why: Self refers to the actual receiver type, so SubBuilder().add("x") is typed as SubBuilder, not Builder, enabling subclass-aware chaining.
python-async · Async (asyncio) · 25 questions
pas1What does this code print?
import asyncio
async def f(n):
await asyncio.sleep(0.01)
return n * 2
async def main():
out = await asyncio.gather(f(3), f(1), f(2))
print(out)
asyncio.run(main())- A[6, 2, 4]✓ Correct answer
- B[2, 4, 6]
- C[1, 2, 3]
- DA coroutine object
Why: gather preserves submission order, so results match the order f(3), f(1), f(2) regardless of completion timing.
pas2What is printed?
async def greet():
return "hi"
result = greet()
print(type(result).__name__)- Acoroutine✓ Correct answer
- Bstr
- Cfunction
- DTask
Why: Calling an async def function returns a coroutine object; the body only runs when awaited or scheduled.
pas3Roughly how long does this take?
import asyncio, time
async def work():
time.sleep(1)
return 42
async def main():
return await asyncio.gather(work(), work(), work())
asyncio.run(main())- A~3 seconds✓ Correct answer
- B~1 second
- C~0 seconds
- DRaises immediately
Why: time.sleep blocks the event loop, so the three coroutines run serially instead of concurrently.
pas4What is printed?
async def boom():
raise ValueError("x")
async def main():
res = await asyncio.gather(boom(), boom(), return_exceptions=True)
print([type(r).__name__ for r in res])
asyncio.run(main())- A['ValueError', 'ValueError']✓ Correct answer
- BRaises ValueError
- C['NoneType', 'NoneType']
- D['Exception', 'Exception']
Why: With return_exceptions=True, gather returns exception instances in place of results instead of raising.
pas5What happens here?
async def slow():
await asyncio.sleep(5)
return 1
async def main():
try:
return await asyncio.wait_for(slow(), timeout=0.1)
except asyncio.TimeoutError:
print("timeout")
asyncio.run(main())- APrints "timeout"✓ Correct answer
- BReturns 1
- CHangs for 5 s
- DRaises ValueError
Why: wait_for cancels the inner coroutine when the timeout expires and raises asyncio.TimeoutError.
pas6What does asyncio.create_task do?
- ASchedules a coroutine to run on the loop and returns a Task✓ Correct answer
- BRuns the coroutine and blocks until done
- CCreates a new event loop
- DSpawns an OS thread
Why: create_task wraps a coroutine in a Task and schedules it concurrently on the running event loop.
pas7What is the bug?
async def f():
return 7
async def main():
print(f())
asyncio.run(main())- AMissing await — prints a coroutine object✓ Correct answer
- BMissing asyncio.run
- Cf must be sync
- Dmain is not awaited
Why: Without await, f() yields a coroutine object instead of its return value, and a RuntimeWarning is emitted.
pas8What is printed?
async def gen():
for i in range(3):
yield i
async def main():
total = 0
async for x in gen():
total += x
print(total)
asyncio.run(main())- A3✓ Correct answer
- B6
- C0
- DSyntaxError
Why: gen yields 0, 1, 2 and async for iterates them, summing to 3.
pas9What does the Semaphore(2) enforce?
async def main():
sem = asyncio.Semaphore(2)
async def worker(i):
async with sem:
await asyncio.sleep(0.1)
return i
return await asyncio.gather(*(worker(i) for i in range(4)))
print(asyncio.run(main()))- AAt most 2 workers inside the block at once✓ Correct answer
- BExactly 2 total runs
- CTwo-second delay
- DTwo retries on failure
Why: Semaphore(2) limits concurrent holders to two; others wait for a slot before entering the async with block.
pas10What is printed?
async def main():
q = asyncio.Queue()
await q.put(1)
await q.put(2)
print(await q.get(), await q.get())
asyncio.run(main())- A1 2✓ Correct answer
- B2 1
- CNone None
- DDeadlock
Why: asyncio.Queue is FIFO by default, so items come out in the order they were put in.
pas11When is asyncio a poor fit?
- ACPU-bound number crunching✓ Correct answer
- BMany concurrent network requests
- CLong-poll websockets
- DSlow database queries via async driver
Why: asyncio shines for I/O-bound concurrency; CPU-bound tasks block the loop and need processes or executors.
pas12What is printed last?
async def hb():
while True:
print("tick")
await asyncio.sleep(1)
async def main():
t = asyncio.create_task(hb())
await asyncio.sleep(0.05)
t.cancel()
try:
await t
except asyncio.CancelledError:
print("done")
asyncio.run(main())- Adone✓ Correct answer
- Btick
- CCancelledError
- DNothing
Why: Cancelling the task injects CancelledError; awaiting the task re-raises it, which the except handles, printing done.
pas13What does asyncio.shield(coro) do?
- AProtects the inner task from cancellation propagated through the shield✓ Correct answer
- BCatches all exceptions silently
- CForces the coroutine to run synchronously
- DPins the task to one CPU
Why: shield wraps a task so cancellation of the awaiter does not cancel the inner task; the inner runs to completion.
pas14Why use async with for httpx.AsyncClient?
async def main():
async with httpx.AsyncClient() as client:
r = await client.get("https://api.example.com/x")
return r.status_code- AEnsures the connection pool is properly closed✓ Correct answer
- BRequired for any await
- CDisables TLS verification
- DMakes requests synchronous
Why: The async context manager guarantees AsyncClient.aclose() runs, releasing pooled connections deterministically.
pas15Difference between httpx.AsyncClient and requests?
- Ahttpx supports async/await; requests is synchronous-only✓ Correct answer
- Brequests is faster always
- CThey are identical APIs
- Dhttpx cannot do POST
Why: httpx offers both sync and async clients with similar APIs; requests has no native asyncio support.
pas16When does TaskGroup's async with exit?
async def main():
async with asyncio.TaskGroup() as tg:
tg.create_task(asyncio.sleep(0.01))
tg.create_task(asyncio.sleep(0.02))
print("ok")
asyncio.run(main())- AAfter every child task finishes✓ Correct answer
- BImmediately after creating tasks
- COnly on cancellation
- DAfter 1 second timeout
Why: TaskGroup waits for all child tasks to complete before exiting; if any fails, others are cancelled.
pas17What is run_in_executor used for here?
import time
def heavy(n):
time.sleep(n); return n
async def main():
loop = asyncio.get_running_loop()
return await loop.run_in_executor(None, heavy, 0.1)
print(asyncio.run(main()))- ARuns blocking sync work off the event loop in a thread✓ Correct answer
- BSpeeds up coroutines
- CReplaces asyncio.run
- DEnables process pool by default
Why: run_in_executor offloads a blocking sync callable to a thread (or process) pool, keeping the loop responsive.
pas18What does this print?
async def f():
return 1
async def main():
t = asyncio.create_task(f())
print(isinstance(t, asyncio.Task), asyncio.iscoroutine(f()))
asyncio.run(main())- ATrue True✓ Correct answer
- BTrue False
- CFalse True
- DFalse False
Why: create_task returns a Task wrapping a coroutine; calling f() again creates a fresh coroutine object.
pas19What is the output order?
from contextlib import asynccontextmanager
@asynccontextmanager
async def conn():
print("open")
yield "c"
print("close")
async def main():
async with conn() as c:
print(c)
asyncio.run(main())- Aopen / c / close✓ Correct answer
- Bc / open / close
- Copen / close / c
- Dclose / c / open
Why: Code before yield runs on enter, the yielded value binds to as, then code after yield runs on exit.
pas20What is observed?
async def f():
raise RuntimeError("oops")
async def main():
asyncio.create_task(f())
await asyncio.sleep(0.05)
print("ok")
asyncio.run(main())- APrints ok and logs an unretrieved task exception warning✓ Correct answer
- BRaises RuntimeError immediately
- CHangs forever
- DPrints "oops"
Why: A fire-and-forget task swallows its exception until garbage collected, when asyncio logs an unretrieved exception warning.
pas21What is printed?
async def gen():
yield 1
yield 2
async def main():
it = gen()
print(await anext(it))
print(await anext(it))
asyncio.run(main())- A1 then 2✓ Correct answer
- B2 then 1
- CStopAsyncIteration
- DA coroutine object twice
Why: anext awaits the async iterator's __anext__, returning each yielded value in order.
pas22How do seq and par differ?
async def task(n):
await asyncio.sleep(0.01)
return n
async def seq():
a = await task(1)
b = await task(2)
return a + b
async def par():
a, b = await asyncio.gather(task(1), task(2))
return a + b- Aseq runs sequentially (~0.02 s); par concurrently (~0.01 s)✓ Correct answer
- BThey behave identically
- Cpar is sequential, seq concurrent
- Dpar requires threads
Why: Awaiting one coroutine then another runs them serially; gather schedules both concurrently and finishes near the slowest.
pas23What is printed?
async def main():
ev = asyncio.Event()
async def waiter():
await ev.wait()
return "go"
t = asyncio.create_task(waiter())
await asyncio.sleep(0.01)
ev.set()
print(await t)
asyncio.run(main())- Ago✓ Correct answer
- BNone
- CHangs forever
- DTimeoutError
Why: Event.set() releases all waiters, so wait() resolves and the task returns "go".
pas24What does timeout=2.0 control?
async def fetch():
async with httpx.AsyncClient(timeout=2.0) as c:
r = await c.get("https://slow.example")
return r.text- ADefault per-request timeout for all stages on this client✓ Correct answer
- BMaximum total client lifetime
- CRetry count
- DConnection pool size
Why: httpx interprets a numeric timeout as the default applied to connect, read, write, and pool stages per request.
pas25Difference between coroutine, Task, and Future?
- ACoroutine: function call result; Task: scheduled coroutine wrapper; Future: low-level result placeholder✓ Correct answer
- BAll three are identical
- CFuture runs synchronously, Task in a thread
- DCoroutine runs on a thread, Task on a process
Why: Task is a Future subclass that drives a coroutine on the loop; Future is the awaitable result primitive used internally.
python-fastapi · FastAPI + httpx · 25 questions
pf1What does FastAPI do when the request is GET /items/abc?
from fastapi import FastAPI
app = FastAPI()
@app.get('/items/{item_id}')
def read(item_id: int):
return {'id': item_id}- AReturns 200 with id="abc"
- BReturns 422 validation error✓ Correct answer
- CReturns 404 not found
- DRaises ValueError at runtime
Why: Path parameter is annotated as int; "abc" cannot be converted, so FastAPI returns 422 with validation details.
pf2Which call uses both default values?
from fastapi import FastAPI
app = FastAPI()
@app.get('/search')
def search(q: str = 'all', limit: int = 10):
return {'q': q, 'limit': limit}- A/search?q=&limit=
- B/search✓ Correct answer
- C/search?q=all
- D/search?limit=10
Why: Omitting both query parameters keeps the function defaults q="all" and limit=10.
pf3What HTTP status does GET /u/-1 produce?
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get('/u/{i}')
def get(i: int):
if i < 0:
raise HTTPException(status_code=404, detail='nope')
return {'i': i}- A200
- B400
- C404✓ Correct answer
- D500
Why: HTTPException(status_code=404) is raised explicitly, FastAPI translates it directly to a 404 response.
pf4Body { "name": "x" } returns which status?
from fastapi import FastAPI
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(min_length=2)
app = FastAPI()
@app.post('/i')
def add(it: Item):
return it- A200
- B400
- C422✓ Correct answer
- D500
Why: Field(min_length=2) fails for "x" (length 1), so Pydantic raises and FastAPI returns 422.
pf5What does the client receive in the JSON body?
from fastapi import FastAPI
from pydantic import BaseModel
class Out(BaseModel):
name: str
app = FastAPI()
@app.get('/me', response_model=Out)
def me():
return {'name': 'Ada', 'token': 'secret'}- A{"name":"Ada","token":"secret"}
- B{"name":"Ada"}✓ Correct answer
- C{"token":"secret"}
- DValidation error 500
Why: response_model filters the output to declared fields, dropping extras like "token" before serialization.
pf6Default status code returned by this endpoint?
from fastapi import FastAPI, status
app = FastAPI()
@app.post('/items', status_code=status.HTTP_201_CREATED)
def create():
return {'ok': True}- A200
- B201✓ Correct answer
- C202
- D204
Why: status_code parameter on the route decorator overrides the default 200, returning 201 Created.
pf7What does GET /i?q=hi return?
from fastapi import FastAPI, Depends
app = FastAPI()
def common(q: str = ''):
return {'q': q}
@app.get('/i')
def list_items(c: dict = Depends(common)):
return c- A{"q":""}
- B{"q":"hi"}✓ Correct answer
- C422 error
- D{"c":{"q":"hi"}}
Why: Depends(common) resolves common(q="hi") and injects the dict, which is returned as JSON.
pf8When does the finally block run?
from fastapi import FastAPI, Depends
app = FastAPI()
def get_db():
db = {'x': 1}
try:
yield db
finally:
db.clear()
@app.get('/')
def r(d=Depends(get_db)):
return d- ABefore the endpoint runs
- BAfter response is sent✓ Correct answer
- CNever, only on errors
- DOn app startup
Why: Yield-based dependencies run cleanup code after the response is delivered, ensuring resources close properly.
pf9Why is async def correct here instead of def?
from fastapi import FastAPI
import httpx
app = FastAPI()
@app.get('/proxy')
async def proxy():
async with httpx.AsyncClient() as c:
r = await c.get('https://api.example.com')
return r.json()- Adef cannot return JSON
- Bawait requires async function✓ Correct answer
- Chttpx is sync only
- DFastAPI requires async
Why: await is only valid inside async functions; httpx.AsyncClient must be awaited, so the endpoint must be async.
pf10When does log() run relative to the response?
from fastapi import FastAPI, BackgroundTasks
app = FastAPI()
def log(msg: str):
open('log.txt', 'a').write(msg)
@app.post('/notify')
def notify(bt: BackgroundTasks):
bt.add_task(log, 'sent')
return {'ok': True}- ABefore response is sent
- BAfter response is sent✓ Correct answer
- CConcurrently with response
- DOnly on next request
Why: BackgroundTasks runs scheduled callables after the response has been returned to the client.
pf11What does this middleware do?
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware('http')
async def add_header(request: Request, call_next):
resp = await call_next(request)
resp.headers['X-App'] = 'demo'
return resp- ABlocks all requests
- BAdds X-App header to every response✓ Correct answer
- CRedirects every request
- DLogs request bodies
Why: The middleware awaits the response then attaches a custom header before returning it to the client.
pf12Which origin can call this API from a browser?
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['https://x.com'],
allow_methods=['*'],
)- AAny origin
- BOnly https://x.com✓ Correct answer
- COnly same origin
- DOnly http://x.com
Why: allow_origins is a strict allowlist; only the listed origin receives permissive CORS headers.
pf13Which content type must the client use?
from fastapi import FastAPI, UploadFile
app = FastAPI()
@app.post('/up')
async def upload(file: UploadFile):
data = await file.read()
return {'size': len(data), 'name': file.filename}- Aapplication/json
- Bapplication/x-www-form-urlencoded
- Cmultipart/form-data✓ Correct answer
- Dtext/plain
Why: UploadFile reads from a multipart/form-data body; FastAPI needs python-multipart installed to parse it.
pf14What must be called before send_text or receive_text?
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket('/ws')
async def ws(websocket: WebSocket):
await websocket.accept()
msg = await websocket.receive_text()
await websocket.send_text(f'echo:{msg}')- Awebsocket.connect()
- Bwebsocket.accept()✓ Correct answer
- Cwebsocket.open()
- DNothing, optional
Why: WebSocket handshake completes only after accept(); messaging methods raise if called beforehand.
pf15Why use StreamingResponse here?
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
def gen():
for i in range(3):
yield f'chunk{i}\n'
@app.get('/s')
def stream():
return StreamingResponse(gen(), media_type='text/plain')- ACompresses output automatically
- BSends body incrementally without buffering✓ Correct answer
- CRequired for JSON
- DAdds CORS headers
Why: StreamingResponse iterates a generator and writes chunks to the wire as they are produced.
pf16What is the full path for list_users?
from fastapi import FastAPI, APIRouter
router = APIRouter(prefix='/v1', tags=['users'])
@router.get('/users')
def list_users():
return []
app = FastAPI()
app.include_router(router)- A/users
- B/v1/users✓ Correct answer
- C/users/v1
- D/list_users
Why: APIRouter prefix is prepended; tags only group endpoints in OpenAPI docs without altering the path.
pf17How is the token expected to arrive?
from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
oauth2 = OAuth2PasswordBearer(tokenUrl='token')
app = FastAPI()
@app.get('/me')
def me(token: str = Depends(oauth2)):
return {'token': token}- AQuery parameter ?token=
- BCookie named token
- CAuthorization: Bearer header✓ Correct answer
- DBody field token
Why: OAuth2PasswordBearer extracts the credential from the Authorization header using the Bearer scheme.
pf18What does TestClient run under the hood?
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
@app.get('/ping')
def ping():
return {'pong': True}
client = TestClient(app)
r = client.get('/ping')- AA real network socket
- BIn-process ASGI calls via httpx✓ Correct answer
- CA separate uvicorn process
- DSelenium browser
Why: TestClient wraps httpx with an ASGI transport, calling the app directly without opening a network port.
pf19What does this pattern replace in modern FastAPI?
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
print('startup')
yield
print('shutdown')
app = FastAPI(lifespan=lifespan)- AMiddleware decorator
- B@app.on_event("startup"/"shutdown")✓ Correct answer
- CDependency injection
- DBackgroundTasks
Why: Lifespan context managers replace the deprecated on_event handlers, unifying startup and shutdown logic.
pf20For input {"name":"ada"}, what is User().name?
from pydantic import BaseModel, field_validator
class User(BaseModel):
name: str
@field_validator('name')
@classmethod
def upper(cls, v: str) -> str:
if not v:
raise ValueError('empty')
return v.upper()- A"ada"
- B"ADA"✓ Correct answer
- CValidationError
- DNone
Why: field_validator returns the transformed value; uppercased "ADA" replaces the original input on the model.
pf21What happens for input {"name":"a","age":1}?
from pydantic import BaseModel, ConfigDict
class User(BaseModel):
model_config = ConfigDict(extra='forbid')
name: str- AAccepted, age ignored
- BValidationError raised✓ Correct answer
- Cage stored on model
- DSilently logs warning
Why: extra="forbid" causes Pydantic v2 to reject undeclared fields with a validation error.
pf22What does asyncio.gather do for the two requests?
import asyncio, httpx
from fastapi import FastAPI
app = FastAPI()
@app.get('/agg')
async def agg():
async with httpx.AsyncClient() as c:
a, b = await asyncio.gather(
c.get('https://x/1'), c.get('https://x/2'))
return {'a': a.status_code, 'b': b.status_code}- ARuns them sequentially
- BRuns them concurrently, awaits both✓ Correct answer
- CSpawns OS threads
- DCaches the second response
Why: gather schedules both coroutines on the event loop; total wait equals the slower request, not the sum.
pf23What is this dependency pattern called?
from fastapi import FastAPI, Depends
def auth(token: str = ''):
return token == 'ok'
def admin(ok: bool = Depends(auth)):
return ok
app = FastAPI()
@app.get('/a')
def page(is_admin: bool = Depends(admin)):
return is_admin- ASub-dependencies✓ Correct answer
- BMiddleware chain
- CBackground tasks
- DLifespan hooks
Why: admin depends on auth, and the route depends on admin — FastAPI resolves the chain top-down.
pf24Why is sync def acceptable here despite blocking?
from fastapi import FastAPI
import time
app = FastAPI()
@app.get('/work')
def work():
time.sleep(2)
return 'done'- AFastAPI ignores blocking
- BIt runs in a threadpool, not the loop✓ Correct answer
- Ctime.sleep is non-blocking
- DIt blocks the event loop fatally
Why: Sync endpoints are dispatched to an anyio threadpool, so blocking calls do not freeze the event loop.
pf25Why use yield rather than return for the session dependency?
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
def get_session():
s = Session()
try:
yield s
finally:
s.close()
app = FastAPI()
@app.get('/u')
def list_u(db: Session = Depends(get_session)):
return db.execute('SELECT 1').all()- Areturn is forbidden in deps
- BTo run cleanup (close) after response✓ Correct answer
- Cyield is faster
- DRequired by SQLAlchemy
Why: Yield lets FastAPI run the finally block after the response, guaranteeing the session is closed even on errors.