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✓ Correct answer
- B3.5
- 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
- B2nd_place✓ Correct answer
- Cmy_var2
- 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 'number'>
- C<class 'float'>✓ Correct answer
- 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
- B Hello
- CHello
- DHELLO✓ Correct answer
Why: .strip() removes surrounding whitespace, then .upper() converts the result to uppercase.
pb5What does this slice print?
s = "python"
print(s[1:4])- Ayth✓ Correct answer
- Bpyt
- 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
- B4
- C3✓ Correct answer
- 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]
- C[4, 5, 1, 2, 3]
- D[1, 2, 3, 4, 5]✓ Correct answer
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)- ATypeError✓ Correct answer
- BPrints (1, 2, 3)
- CPrints (9, 2, 3)
- 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
- B0✓ Correct answer
- CKeyError
- 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 items
- CMembership of keys✓ Correct answer
- 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
- B1
- C2
- D3✓ Correct answer
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))- A1✓ Correct answer
- B4
- C5
- 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
- B6
- C10✓ Correct answer
- 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"
- Ca 0
- D0 a✓ Correct answer
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')]✓ Correct answer
- B[(1, 'x'), (2, 'y'), (3, None)]
- 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"))- ATypeError
- BSam, Hi
- CHi, Sam✓ Correct answer
- 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
- CTypeError
- D10✓ Correct answer
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__)- ANoneType✓ Correct answer
- BNone
- 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))- ATypeError
- BFalse
- CTrue✓ Correct answer
- 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
- BValueError
- Cabc
- D-1✓ Correct answer
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.0✓ Correct answer
- B4
- 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)- Awolf✓ Correct answer
- Bcanine
- 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
- BBA✓ Correct answer
- CA
- 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)- A<property>
- B212
- C212.0✓ Correct answer
- 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())- A23 Math
- B5 cls
- CTypeError
- D5 Math✓ Correct answer
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')- Amid, in, out
- Bin, mid, out✓ Correct answer
- 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))- A2 3
- B1 1
- C1 2✓ Correct answer
- 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')- Aonly f
- Bv then e then f
- Ce then f
- Dv then f✓ Correct answer
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, 4, 9, 16, 25]
- B[1, 9, 25]✓ Correct answer
- 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[2, 3, 4]
- B[1, 2]
- C[3, 4]✓ Correct answer
- 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))- ATypeError
- B10
- C32
- D25✓ Correct answer
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), ('m', 1)]
- B[('i', 4), ('s', 4)]✓ Correct answer
- 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)- A1 a
- B0 a
- C10 a✓ Correct answer
- 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))- ASyntaxError
- Bzero
- Cother
- Dint✓ Correct answer
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], [3, 4]]
- B[[1, 2, 9], [3, 4]]✓ Correct answer
- 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']
- B['a', 'b', 'c', 'd']
- C['a', 'b', 'c,d']✓ Correct answer
- 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)- ATypeError
- B{'x': 1, 'y': 2, 'z': 3}
- C{'y': 9, 'z': 3}
- D{'x': 1, 'y': 9, 'z': 3}✓ Correct answer
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[2]
- B[1, 2]✓ Correct answer
- 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))- AKeyError
- B{'a': 1, 'b': 1, 'c': 1}
- C{'a': 2, 'b': 1, 'c': 1}✓ Correct answer
- 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))- A14
- B10
- C24
- D20✓ Correct answer
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()))- AYes, prints HELLO✓ Correct answer
- BNo, En does not inherit Greeter
- 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 ['x']✓ Correct answer
- CPrints []
- 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
- Bbool:True
- Cint:True✓ Correct answer
- 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
- BFaster I/O than asyncio
- CThread-safe user code
- DOnly one thread executes Python bytecode at a time✓ Correct answer
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 None
- CValid, prints 0✓ Correct answer
- 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
- BIt replaces try/except
- CTo suppress IOError
- DTo manage a dynamic number of context managers✓ Correct answer
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)- A10✓ Correct answer
- B5
- 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,4),(2,2)]
- C[(1,[1,1]),(2,[2,2]),(1,[1,1])]✓ Correct answer
- 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())- AReferenceError
- BTrue then <Node object>
- CFalse then None
- DTrue then None✓ Correct answer
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 can execute arbitrary code on load✓ Correct answer
- Cpickle is safe to load from untrusted sources
- 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
- B2
- C1✓ Correct answer
- 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')
- BBufferError
- CTypeError: bytes immutable
- Dbytearray(b'Hello')✓ Correct answer
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)- ATypeError: metaclass conflict
- BAttributeError
- CNone
- Dhi✓ Correct answer
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)- Ax-axis:1✓ Correct answer
- Borigin
- 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
- BRuntime performance
- CThe full parameter signature of the wrapped callable✓ Correct answer
- 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[2, 3, 4]
- B[10, 12, 14]
- C[12, 14, 16, 18]
- D[14, 16, 18]✓ Correct answer
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 preserves the subclass type for fluent chaining✓ Correct answer
- BSelf is faster at runtime
- 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__)- Astr
- Bcoroutine✓ Correct answer
- 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~0 seconds
- B~1 second
- C~3 seconds✓ Correct answer
- 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['Exception', 'Exception']
- BRaises ValueError
- C['NoneType', 'NoneType']
- D['ValueError', 'ValueError']✓ Correct answer
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?
- ARuns the coroutine and blocks until done
- BSchedules a coroutine to run on the loop and returns a Task✓ Correct answer
- 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())- Af must be sync
- BMissing asyncio.run
- CMissing await — prints a coroutine object✓ Correct answer
- 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())- ASyntaxError
- B6
- C0
- D3✓ Correct answer
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())- A2 1
- B1 2✓ Correct answer
- 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?
- ALong-poll websockets
- BMany concurrent network requests
- CCPU-bound number crunching✓ Correct answer
- 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())- ANothing
- Btick
- CCancelledError
- Ddone✓ Correct answer
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- ARequired for any await
- BEnsures the connection pool is properly closed✓ Correct answer
- 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?
- AThey are identical APIs
- Brequests is faster always
- Chttpx supports async/await; requests is synchronous-only✓ Correct answer
- 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 1 second timeout
- BImmediately after creating tasks
- COnly on cancellation
- DAfter every child task finishes✓ Correct answer
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 False
- BTrue True✓ Correct answer
- 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 / close / c
- Bc / open / close
- Copen / c / close✓ Correct answer
- 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 "oops"
- BRaises RuntimeError immediately
- CHangs forever
- DPrints ok and logs an unretrieved task exception warning✓ Correct answer
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- AThey behave identically
- Bseq runs sequentially (~0.02 s); par concurrently (~0.01 s)✓ Correct answer
- 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())- AHangs forever
- BNone
- Cgo✓ Correct answer
- 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- AConnection pool size
- BMaximum total client lifetime
- CRetry count
- DDefault per-request timeout for all stages on this client✓ Correct answer
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 422 validation error✓ Correct answer
- BReturns 200 with id="abc"
- 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
- C500
- D422✓ Correct answer
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"}✓ Correct answer
- B{"name":"Ada","token":"secret"}
- 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":""}
- B422 error
- C{"q":"hi"}✓ Correct answer
- 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
- BOn app startup
- CNever, only on errors
- DAfter response is sent✓ Correct answer
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()- Aawait requires async function✓ Correct answer
- Bdef cannot return JSON
- 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
- BRedirects every request
- CAdds X-App header to every response✓ Correct answer
- 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 http://x.com
- COnly same origin
- DOnly https://x.com✓ Correct answer
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}- Amultipart/form-data✓ Correct answer
- Bapplication/x-www-form-urlencoded
- Capplication/json
- 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
- BRequired for JSON
- CSends body incrementally without buffering✓ Correct answer
- 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/list_users
- C/users/v1
- D/v1/users✓ Correct answer
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}- AAuthorization: Bearer header✓ Correct answer
- BCookie named token
- CQuery parameter ?token=
- 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
- BDependency injection
- C@app.on_event("startup"/"shutdown")✓ Correct answer
- 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"
- BNone
- CValidationError
- D"ADA"✓ Correct answer
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- AValidationError raised✓ Correct answer
- BAccepted, age ignored
- 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- ABackground tasks
- BMiddleware chain
- CSub-dependencies✓ Correct answer
- 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 blocks the event loop fatally
- Ctime.sleep is non-blocking
- DIt runs in a threadpool, not the loop✓ Correct answer
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()- ATo run cleanup (close) after response✓ Correct answer
- Breturn is forbidden in deps
- 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.