Naucz się Pythona — każde pytanie, każda odpowiedź
Wszystkie 125 pytań na 5 poziomach z przykładami kodu, poprawnymi odpowiedziami i szczegółowymi wyjaśnieniami. Za darmo, bez logowania, w pełni zaindeksowane.
Kompletny przewodnik po Pythonie: od podstawowych typów danych i sterowania po dataclasses, dekoratory i contextlib, asyncio, FastAPI oraz Pydantic. Każdy wpis pokazuje uruchomiony kod, poprawną odpowiedź i regułę, która o tym decyduje.
python-basic · Podstawy · 25
pb1Co wypisze ten kod?
x = 7
y = 2
print(x // y)- A3.5
- B3✓ Poprawna odpowiedź
- C4
- D3.0
Dlaczego: Operator // to dzielenie całkowite z zaokrągleniem w dół, zwraca 3 dla intów.
pb2Który identyfikator jest NIEPOPRAWNY w Pythonie?
- A_value
- Bmy_var2
- C2nd_place✓ Poprawna odpowiedź
- DCamelCase
Dlaczego: Identyfikatory nie mogą zaczynać się od cyfry; muszą zaczynać się od litery lub podkreślenia.
pb3Jaki typ zostanie wypisany?
print(type(3 / 2))- A<class 'int'>
- B<class 'float'>✓ Poprawna odpowiedź
- C<class 'number'>
- D<class 'double'>
Dlaczego: Operator / w Pythonie 3 zawsze zwraca float, nawet dla operandów całkowitych.
pb4Co wypisze ten kod?
s = " Hello "
print(s.strip().upper())- A HELLO
- BHELLO✓ Poprawna odpowiedź
- CHello
- D Hello
Dlaczego: .strip() usuwa otaczające białe znaki, potem .upper() zamienia na wielkie litery.
pb5Co wypisze to wycinanie?
s = "python"
print(s[1:4])- Apyt
- Byth✓ Poprawna odpowiedź
- Cytho
- Dthon
Dlaczego: Wycinek s[1:4] bierze indeksy 1, 2, 3 — koniec jest wyłączny.
pb6Co wypisze ten f-string?
name = "Ada"
print(f"Hi, {name}!")- AHi, {name}!
- BHi, Ada!✓ Poprawna odpowiedź
- CHi, "Ada"!
- DSyntaxError
Dlaczego: F-stringi wstawiają wartość wyrażeń w klamrach do napisu.
pb7Co wypisze ten kod?
xs = [1, 2]
xs.append([3, 4])
print(len(xs))- A2
- B3✓ Poprawna odpowiedź
- C4
- DTypeError
Dlaczego: append dodaje jeden element (listę wewnętrzną) — długość to 3, nie 4.
pb8Co wypisze ten kod?
xs = [1, 2, 3]
xs.extend([4, 5])
print(xs)- A[1, 2, 3, [4, 5]]
- B[1, 2, 3, 4, 5]✓ Poprawna odpowiedź
- C[4, 5, 1, 2, 3]
- D[1, 2, 3]
Dlaczego: extend iteruje po argumencie i dodaje każdy element osobno do listy.
pb9Co się stanie po uruchomieniu kodu?
t = (1, 2, 3)
t[0] = 9
print(t)- AWypisze (9, 2, 3)
- BWypisze (1, 2, 3)
- CTypeError✓ Poprawna odpowiedź
- DIndexError
Dlaczego: Krotki są niemutowalne; przypisanie do indeksu zgłasza TypeError.
pb10Co wypisze ten kod?
d = {"a": 1, "b": 2}
print(d.get("c", 0))- ANone
- BKeyError
- C0✓ Poprawna odpowiedź
- D1
Dlaczego: dict.get(klucz, domyślna) zwraca wartość domyślną, gdy klucza nie ma.
pb11Co sprawdza operator in na słowniku?
d = {"x": 1}
print("x" in d)- AObecność wartości
- BObecność kluczy✓ Poprawna odpowiedź
- CObecność par
- DZawsze False
Dlaczego: Dla słowników operator in sprawdza istnienie klucza, nie wartości.
pb12Co wypisze ten kod?
s = {1, 2, 2, 3, 3, 3}
print(len(s))- A6
- B3✓ Poprawna odpowiedź
- C2
- D1
Dlaczego: Zbiory przechowują tylko unikalne elementy, duplikaty są usuwane, zostaje {1, 2, 3}.
pb13Co wypisze ten kod?
vals = [0, "", None, [], "x"]
truthy = [v for v in vals if v]
print(len(truthy))- A5
- B4
- C1✓ Poprawna odpowiedź
- D0
Dlaczego: 0, "", None i [] są fałszywe; tylko "x" przechodzi przez filtr.
pb14Co wypisze ten kod?
x = 10
if x > 20:
print("A")
elif x > 5:
print("B")
else:
print("C")- AA
- BB✓ Poprawna odpowiedź
- CC
- DBC
Dlaczego: Wykonuje się tylko pierwsza pasująca gałąź; 10 > 5 jest prawdą, więc "B".
pb15Co wypisze ten kod?
total = 0
for i in range(1, 5):
total += i
print(total)- A15
- B10✓ Poprawna odpowiedź
- C6
- D4
Dlaczego: range(1, 5) daje 1, 2, 3, 4 (koniec wyłączny); suma to 10.
pb16Jaka jest pierwsza wypisana linia?
names = ["a", "b", "c"]
for i, n in enumerate(names):
print(i, n)- A1 a
- B0 a✓ Poprawna odpowiedź
- Ca 0
- D0 "a"
Dlaczego: enumerate zwraca pary (indeks, wartość), zaczynając od 0 domyślnie.
pb17Co wypisze ten kod?
a = [1, 2, 3]
b = ["x", "y"]
print(list(zip(a, b)))- A[(1, 'x'), (2, 'y'), (3, None)]
- B[(1, 'x'), (2, 'y')]✓ Poprawna odpowiedź
- C[1, 'x', 2, 'y', 3]
- DBłąd
Dlaczego: zip kończy na najkrótszym iterowalnym, więc trzeci element a jest pomijany.
pb18Co wypisze ta składnia listy?
squares = [x*x for x in range(4)]
print(squares)- A[1, 4, 9, 16]
- B[0, 1, 4, 9]✓ Poprawna odpowiedź
- C[0, 1, 2, 3]
- D[1, 2, 4, 8]
Dlaczego: range(4) daje 0, 1, 2, 3; po podniesieniu do kwadratu wynik to [0, 1, 4, 9].
pb19Co wypisze ten kod?
def greet(name, greeting="Hi"):
return f"{greeting}, {name}"
print(greet("Sam"))- AHi, Sam✓ Poprawna odpowiedź
- BSam, Hi
- CTypeError
- DHi, name
Dlaczego: Argumenty domyślne są używane, gdy wywołujący ich nie podaje; greeting to "Hi".
pb20Co wypisze ten kod?
def total(*args, **kwargs):
return sum(args) + sum(kwargs.values())
print(total(1, 2, x=3, y=4))- A3
- B7
- C10✓ Poprawna odpowiedź
- DTypeError
Dlaczego: *args zbiera (1, 2), a **kwargs {x:3, y:4}; sumy dają 3 + 7 = 10.
pb21Co wypisze ten kod?
def f():
pass
print(type(f()).__name__)- ANone
- BNoneType✓ Poprawna odpowiedź
- Cfunction
- Dvoid
Dlaczego: Funkcja bez return zwraca None, którego klasa nazywa się NoneType.
pb22Co wypisze ten kod?
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b, a is b)- ATrue True
- BTrue False✓ Poprawna odpowiedź
- CFalse True
- DFalse False
Dlaczego: == porównuje wartości (równe); is sprawdza tożsamość — to różne obiekty.
pb23Co wypisze ten kod?
print(isinstance(True, int))- ATrue✓ Poprawna odpowiedź
- BFalse
- CTypeError
- DNone
Dlaczego: W Pythonie bool dziedziczy po int, więc isinstance(True, int) zwraca True.
pb24Co wypisze ten kod?
try:
x = int("abc")
except ValueError:
x = -1
print(x)- A0
- B-1✓ Poprawna odpowiedź
- Cabc
- DValueError
Dlaczego: int("abc") zgłasza ValueError, który jest złapany i ustawia x na -1.
pb25Co wypisze ten kod?
import math
print(math.sqrt(16))- A4
- B4.0✓ Poprawna odpowiedź
- C16
- DImportError
Dlaczego: math.sqrt zawsze zwraca float, więc sqrt(16) wypisuje 4.0, a nie 4.
python-medium · Średniozaawansowany · 25
pm1Co to wypisze?
class Dog:
species = 'canine'
def __init__(self, name):
self.name = name
a = Dog('Rex')
Dog.species = 'wolf'
print(a.species)- Acanine
- Bwolf✓ Poprawna odpowiedź
- CRex
- DAttributeError
Dlaczego: species to atrybut klasy; zmiana na klasie widoczna jest u instancji bez własnego nadpisania.
pm2Co to wypisze?
class A:
def hi(self): return 'A'
class B(A):
def hi(self): return 'B' + super().hi()
print(B().hi())- AB
- BA
- CBA✓ Poprawna odpowiedź
- DAB
Dlaczego: B.hi zwraca "B" + super().hi() (czyli A.hi -> "A"), więc wynikiem jest "BA".
pm3Co to wypisze?
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✓ Poprawna odpowiedź
- B212
- C<property>
- DTypeError
Dlaczego: @property pozwala wywołać f bez nawiasów; 100*9/5+32 to 212.0 (dzielenie zmiennoprzecinkowe).
pm4Co to wypisze?
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✓ Poprawna odpowiedź
- B5 cls
- CTypeError
- D23 Math
Dlaczego: @staticmethod nie ma niejawnych argumentów; @classmethod dostaje cls związane z klasą.
pm5Co to wypisze?
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✓ Poprawna odpowiedź
- Bhi ann
- CHI ann
- DTypeError
Dlaczego: Dekorator owija greet; wynik "hi ann" jest zamieniany na wielkie litery: "HI ANN".
pm6Jaka jest kolejność wyjścia?
class Open:
def __enter__(self):
print('in'); return self
def __exit__(self, *a):
print('out')
with Open():
print('mid')- Ain, mid, out✓ Poprawna odpowiedź
- Bmid, in, out
- Cin, out, mid
- Dout, mid, in
Dlaczego: Najpierw __enter__, potem ciało with, na końcu __exit__ przy wyjściu z bloku.
pm7Co to wypisze?
def gen():
yield 1
yield 2
yield 3
g = gen()
print(next(g), next(g))- A1 2✓ Poprawna odpowiedź
- B1 1
- C2 3
- D1 2 3
Dlaczego: Każde next() przesuwa generator do kolejnego yield, zwracając 1 a potem 2.
pm8Co to wypisze?
try:
raise ValueError('a')
except ValueError:
print('v')
else:
print('e')
finally:
print('f')- Av potem f✓ Poprawna odpowiedź
- Bv potem e potem f
- Ce potem f
- Dtylko f
Dlaczego: else uruchamia się tylko bez wyjątku; finally wykonuje się zawsze.
pm9Co to wypisze?
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]✓ Poprawna odpowiedź
- B[0, 1]
- C[1, 2, 3]
- D[]
Dlaczego: list() iteruje aż do StopIteration; zwracane są 1 i 2 zanim i osiągnie 2.
pm10Co to wypisze?
nums = [1, 2, 3, 4, 5]
print([x*x for x in nums if x % 2])- A[1, 9, 25]✓ Poprawna odpowiedź
- B[1, 4, 9, 16, 25]
- C[4, 16]
- D[1, 3, 5]
Dlaczego: Lista składana wybiera liczby nieparzyste i podnosi je do kwadratu: 1, 9, 25.
pm11Co to wypisze?
nums = [1, 2, 3, 4]
print(list(filter(lambda x: x > 2, nums)))- A[3, 4]✓ Poprawna odpowiedź
- B[1, 2]
- C[2, 3, 4]
- D[True, True]
Dlaczego: filter zachowuje elementy, dla których lambda jest prawdziwa; tylko 3 i 4 są > 2.
pm12Co to wypisze?
from functools import partial
def power(base, exp): return base ** exp
square = partial(power, exp=2)
print(square(5))- A25✓ Poprawna odpowiedź
- B10
- C32
- DTypeError
Dlaczego: partial ustala exp=2; square(5) liczy 5**2, czyli 25.
pm13Co to wypisze?
from pathlib import Path
p = Path('/tmp/data.txt')
print(p.suffix, p.stem)- A.txt data✓ Poprawna odpowiedź
- Btxt data
- C.txt /tmp/data
- Ddata .txt
Dlaczego: Path.suffix zawiera kropkę (".txt"); Path.stem to nazwa bez rozszerzenia ("data").
pm14Co to wypisze?
from collections import Counter
print(Counter('mississippi').most_common(2))- A[('i', 4), ('s', 4)]✓ Poprawna odpowiedź
- B[('i', 4), ('m', 1)]
- C[('s', 4), ('i', 4)]
- D[('p', 2), ('m', 1)]
Dlaczego: "mississippi" ma cztery i oraz cztery s; most_common(2) zwraca te dwie pary.
pm15Jaka jest pierwsza wypisana linia?
for i, v in enumerate(['a', 'b', 'c'], start=10):
print(i, v)- A10 a✓ Poprawna odpowiedź
- B0 a
- C1 a
- D10 c
Dlaczego: enumerate(start=10) zaczyna od 10, więc pierwsza para to (10, "a").
pm16Co to wypisze?
def classify(x):
match x:
case 0: return 'zero'
case int(): return 'int'
case _: return 'other'
print(classify(5))- Aint✓ Poprawna odpowiedź
- Bzero
- Cother
- DSyntaxError
Dlaczego: 5 nie jest 0, ale pasuje do int(), więc funkcja zwraca "int" przed wildcardem.
pm17Co to wypisze?
pi = 3.14159
print(f'{pi:.2f}')- A3.14✓ Poprawna odpowiedź
- B3.142
- C3.14159
- D3.1
Dlaczego: Specyfikator .2f zaokrągla liczbę do dwóch miejsc po przecinku.
pm18Co to wypisze?
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
b[0].append(9)
print(a)- A[[1, 2, 9], [3, 4]]✓ Poprawna odpowiedź
- B[[1, 2], [3, 4]]
- C[[1, 2], [3, 4, 9]]
- D[[1, 2, 9], [3, 4, 9]]
Dlaczego: copy.copy jest płytka; wewnętrzne listy są współdzielone, więc zmiana b[0] dotyczy a[0].
pm19Co to wypisze?
print('a,b,c,d'.split(',', maxsplit=2))- A['a', 'b', 'c,d']✓ Poprawna odpowiedź
- B['a', 'b', 'c', 'd']
- C['a,b', 'c', 'd']
- D['a', 'b,c,d']
Dlaczego: maxsplit=2 daje trzy elementy; reszta "c,d" pozostaje jako jeden element.
pm20Co to wypisze?
a = {'x': 1, 'y': 2}
b = {'y': 9, 'z': 3}
print(a | b)- A{'x': 1, 'y': 9, 'z': 3}✓ Poprawna odpowiedź
- B{'x': 1, 'y': 2, 'z': 3}
- C{'y': 9, 'z': 3}
- DTypeError
Dlaczego: Operator | scala słowniki; przy konflikcie klucza wygrywa prawy operand, więc y=9.
pm21Co to wypisze?
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
print(sorted(pairs, key=lambda p: p[1]))- A[(3, 'a'), (1, 'b'), (2, 'c')]✓ Poprawna odpowiedź
- B[(1, 'b'), (2, 'c'), (3, 'a')]
- C[(1, 'b'), (3, 'a'), (2, 'c')]
- D[(2, 'c'), (1, 'b'), (3, 'a')]
Dlaczego: Klucz wybiera drugi element krotki, sortując alfabetycznie po literze.
pm22Jaka jest druga wypisana linia?
def add(x, items=[]):
items.append(x)
return items
print(add(1))
print(add(2))- A[1, 2]✓ Poprawna odpowiedź
- B[2]
- C[1]
- D[2, 1]
Dlaczego: Mutowalne argumenty domyślne są dzielone między wywołaniami; ta sama lista zbiera 1, potem 2.
pm23Co to wypisze?
from collections import defaultdict
d = defaultdict(int)
for c in 'abca':
d[c] += 1
print(dict(d))- A{'a': 2, 'b': 1, 'c': 1}✓ Poprawna odpowiedź
- B{'a': 1, 'b': 1, 'c': 1}
- CKeyError
- D{'a': 2}
Dlaczego: defaultdict(int) tworzy brakujące klucze z 0; zliczanie "abca" daje a=2, b=1, c=1.
pm24Co to wypisze?
from functools import reduce
print(reduce(lambda a, b: a + b, [1, 2, 3, 4], 10))- A20✓ Poprawna odpowiedź
- B10
- C24
- D14
Dlaczego: reduce startuje od 10 i dodaje 1+2+3+4=10, dając łącznie 20.
pm25Co to wypisze?
from collections import deque
d = deque([1, 2, 3])
d.appendleft(0)
d.append(4)
print(list(d))- A[0, 1, 2, 3, 4]✓ Poprawna odpowiedź
- B[1, 2, 3, 0, 4]
- C[4, 0, 1, 2, 3]
- D[0, 4, 1, 2, 3]
Dlaczego: appendleft dodaje 0 z przodu; append dokłada 4 z tyłu, dając [0, 1, 2, 3, 4].
python-advanced · Zaawansowany · 25
pa1Czy to się sprawdza typowo i co wypisuje?
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()))- ANie, En nie dziedziczy z Greeter
- BTak, wypisuje HELLO✓ Poprawna odpowiedź
- CTak, wypisuje hello
- DTypeError w runtime
Dlaczego: Protocol używa typowania strukturalnego: każda klasa z pasującymi metodami spełnia go bez jawnego dziedziczenia.
pa2Co się dzieje z tą zamrożoną 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 przy append
- BWypisuje []
- CWypisuje ['x']✓ Poprawna odpowiedź
- DTypeError przy tworzeniu
Dlaczego: frozen=True blokuje przypisanie atrybutów, ale mutowalne obiekty wskazywane przez atrybuty można nadal modyfikować w miejscu.
pa3Co wypisuje fmt(True)?
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✓ Poprawna odpowiedź
- Cbool:True
- DTypeError
Dlaczego: bool jest podklasą int, więc singledispatch rozwiązuje True do implementacji int poprzez MRO.
pa4Co gwarantuje GIL w Pythonie?
- ARównoległe wykonanie wątków na CPU
- BTylko jeden wątek wykonuje bytecode jednocześnie✓ Poprawna odpowiedź
- CBezpieczny kod użytkownika
- DSzybsze I/O niż asyncio
Dlaczego: GIL serializuje wykonanie bytecode do jednego wątku, blokując równoległość CPU, ale nie czyniąc kodu thread-safe.
pa5Co jest wypisane?
from itertools import accumulate
import operator
nums = [1, 2, 3, 4]
print(list(accumulate(nums, operator.mul)))- A[1, 2, 6, 24]✓ Poprawna odpowiedź
- B[1, 3, 6, 10]
- C[24]
- D[1, 2, 3, 4]
Dlaczego: accumulate zwraca kolejne wyniki: 1, 1*2, 1*2*3, 1*2*3*4 używając operatora mnożenia.
pa6Co się dzieje?
class C:
__slots__ = ('x',)
c = C()
c.x = 1
c.y = 2
print(c.x, c.y)- AWypisuje 1 2
- BAttributeError na c.y = 2✓ Poprawna odpowiedź
- CTypeError przy definicji
- DWypisuje 1 None
Dlaczego: __slots__ wyłącza __dict__ instancji, więc przypisanie atrybutu spoza listy zgłasza AttributeError.
pa7Czy to poprawne i co wypisuje?
from typing import TypedDict, NotRequired
class User(TypedDict):
name: str
age: NotRequired[int]
u: User = {'name': 'Ada'}
print(u.get('age', 0))- ABłąd typu: brak age
- BPoprawne, wypisuje 0✓ Poprawna odpowiedź
- CPoprawne, wypisuje None
- DRuntime KeyError
Dlaczego: NotRequired oznacza klucz TypedDict jako opcjonalny, więc pominięcie age jest poprawne; .get zwraca domyślne 0.
pa8Po co tutaj ExitStack?
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__)- AAby otwierać pliki równolegle
- BAby zarządzać dynamiczną liczbą menedżerów kontekstu✓ Poprawna odpowiedź
- CAby tłumić IOError
- DZastępuje try/except
Dlaczego: ExitStack pozwala wejść w nieznaną liczbę menedżerów kontekstu w runtime i gwarantuje ich poprawne zamknięcie.
pa9Co wypisuje print?
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✓ Poprawna odpowiedź
- C0
- DAttributeError
Dlaczego: __set__ deskryptora zapisuje 5*2 w _x; __get__ czyta _x, zwracając 10.
pa10Co jest wypisane?
from enum import StrEnum, auto
class Color(StrEnum):
RED = auto()
BLUE = auto()
print(Color.RED == 'red', Color.RED.value)- AFalse 1
- BTrue red✓ Poprawna odpowiedź
- CTrue RED
- DFalse red
Dlaczego: StrEnum.auto() generuje nazwę członka małymi literami; członkowie StrEnum są równi swojej wartości tekstowej.
pa11Co produkuje itertools.groupby?
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])]✓ Poprawna odpowiedź
- C[(1,4),(2,2)]
- D[(1,[1,1,1,1,1,1])]
Dlaczego: groupby grupuje tylko sąsiednie równe elementy, więc nieprzylegające serie tworzą osobne grupy.
pa12Co jest wypisane?
import weakref
class Node: pass
n = Node()
r = weakref.ref(n)
print(r() is n)
del n
print(r())- ATrue potem None✓ Poprawna odpowiedź
- BTrue potem <Node object>
- CFalse potem None
- DReferenceError
Dlaczego: weakref nie utrzymuje obiektu przy życiu; po usunięciu silnej referencji wywołanie weakref zwraca None.
pa13Jaki jest wynik?
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✓ Poprawna odpowiedź
- B3
- CTypeError
- DBox[int]
Dlaczego: Generic[T] umożliwia typowanie parametryczne; w runtime typy są wymazywane, a 3 + 1 daje 4.
pa14Które stwierdzenie o pickle vs json jest PRAWDZIWE?
- Ajson serializuje dowolne obiekty Pythona
- Bpickle jest bezpieczny dla nieufnych źródeł
- Cpickle może wykonać dowolny kod przy load✓ Poprawna odpowiedź
- Djson zachowuje rozróżnienie tuple/list
Dlaczego: pickle.load może wykonać dowolny kod przez spreparowane dane; nigdy nie odpicklowywać niezaufanych danych. json jest bezpieczny.
pa15Ile razy wypisane jest "compute"?
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✓ Poprawna odpowiedź
- C2
- DBłąd: wymaga __slots__
Dlaczego: cached_property liczy raz na instancję i zapisuje wynik w __dict__ instancji, kolejne dostępy pomijają obliczenia.
pa16Co to wypisuje?
ba = bytearray(b'hello')
mv = memoryview(ba)
mv[0] = ord('H')
print(ba)- Abytearray(b'hello')
- Bbytearray(b'Hello')✓ Poprawna odpowiedź
- CTypeError: bytes niemutowalne
- DBufferError
Dlaczego: memoryview współdzieli bufor bytearray (mutowalny), więc zapis przez niego zmienia oryginał w miejscu.
pa17Co zwraca re.findall?
import re
text = 'a1 b22 c333'
print(re.findall(r'\d+', text))- A['1', '22', '333']✓ Poprawna odpowiedź
- Biterator obiektów Match
- C['a1', 'b22', 'c333']
- D[1, 22, 333]
Dlaczego: findall zwraca listę dopasowanych stringów, a finditer iterator obiektów Match z pozycjami i grupami.
pa18Co tu robi assert_never?
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))- AZawsze rzuca w runtime
- BStatyczna kompletność; błąd typu gdy brak przypadków✓ Poprawna odpowiedź
- CTłumi ostrzeżenia
- DAsercja shape == None
Dlaczego: assert_never mówi checkerowi, że gałąź jest nieosiągalna; pominięty przypadek Literal daje błąd typowania.
pa19Najlepszy wybór dla zadań CPU-bound w CPythonie?
- Athreading
- Basyncio
- Cmultiprocessing✓ Poprawna odpowiedź
- Dconcurrent.futures.ThreadPoolExecutor
Dlaczego: multiprocessing tworzy osobne procesy z własnym GIL/interpreterem, dając prawdziwą równoległość CPU niedostępną dla wątków/asyncio.
pa20Co jest wypisane?
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✓ Poprawna odpowiedź
- BAttributeError
- CNone
- DTypeError: konflikt metaklasy
Dlaczego: Metaklasa wstrzykuje greeting do przestrzeni klasy przed jej utworzeniem, więc A.greeting == "hi".
pa21Czym jest 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✓ Poprawna odpowiedź
- Cy-axis:0
- Dother
Dlaczego: Wzorce sprawdzane od góry; (1,0) nie pasuje do (0,0), pasuje do (x,0) z x=1, daje "x-axis:1".
pa22Po co ContextVar zamiast globalnej?
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())- ASzybsze niż globalne
- BIzolacja per task/coroutine bez jawnego przekazywania✓ Poprawna odpowiedź
- CZamiennik blokady thread-safe
- DWymagane przez asyncio.run
Dlaczego: ContextVar wiąże wartość z bieżącym kontekstem (taskiem), współbieżne taski widzą niezależne wartości bez przekazywania w argumentach.
pa23Co zachowuje ParamSpec?
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- ATylko typ zwracany
- BPełną sygnaturę parametrów wrappowanej funkcji✓ Poprawna odpowiedź
- CWydajność runtime
- DNazwę funkcji
Dlaczego: ParamSpec wychwytuje zarówno parametry pozycyjne, jak i kluczowe, aby dekoratory przekazywały je z pełną wiernością typów.
pa24Co to wypisuje?
from itertools import islice, count
print(list(islice(count(10, 2), 2, 5)))- A[14, 16, 18]✓ Poprawna odpowiedź
- B[10, 12, 14]
- C[12, 14, 16, 18]
- D[2, 3, 4]
Dlaczego: count(10,2) daje 10,12,14,16,18,...; islice start=2 stop=5 bierze indeksy 2,3,4 → 14,16,18.
pa25Po co zwracać Self zamiast "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 jest szybsze w runtime
- BSelf zachowuje typ podklasy dla fluent chaining✓ Poprawna odpowiedź
- CSelf zabrania dziedziczenia
- DSą równoważne
Dlaczego: Self odnosi się do faktycznego typu odbiorcy, więc SubBuilder().add("x") ma typ SubBuilder, nie Builder, umożliwiając łańcuchowanie z podklasą.
python-async · Async (asyncio) · 25
pas1Co wypisze ten kod?
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]✓ Poprawna odpowiedź
- B[2, 4, 6]
- C[1, 2, 3]
- DObiekt coroutine
Dlaczego: gather zachowuje kolejność zgłoszenia, więc wynik odpowiada kolejności f(3), f(1), f(2) niezależnie od czasu ukończenia.
pas2Co zostanie wypisane?
async def greet():
return "hi"
result = greet()
print(type(result).__name__)- Acoroutine✓ Poprawna odpowiedź
- Bstr
- Cfunction
- DTask
Dlaczego: Wywołanie funkcji async def zwraca obiekt coroutine; ciało wykonuje się dopiero po await lub zaplanowaniu.
pas3Ile mniej więcej to trwa?
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 sekundy✓ Poprawna odpowiedź
- B~1 sekunda
- C~0 sekund
- DNatychmiast wyjątek
Dlaczego: time.sleep blokuje pętlę zdarzeń, więc trzy korutyny wykonują się szeregowo zamiast współbieżnie.
pas4Co zostanie wypisane?
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']✓ Poprawna odpowiedź
- BRzuca ValueError
- C['NoneType', 'NoneType']
- D['Exception', 'Exception']
Dlaczego: Z return_exceptions=True gather zwraca instancje wyjątków zamiast je rzucać.
pas5Co się tutaj dzieje?
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())- AWypisuje "timeout"✓ Poprawna odpowiedź
- BZwraca 1
- CZawiesza się na 5 s
- DRzuca ValueError
Dlaczego: wait_for anuluje wewnętrzną korutynę po przekroczeniu czasu i rzuca asyncio.TimeoutError.
pas6Co robi asyncio.create_task?
- APlanuje korutynę w pętli i zwraca Task✓ Poprawna odpowiedź
- BUruchamia korutynę i blokuje aż do końca
- CTworzy nową pętlę zdarzeń
- DTworzy wątek systemowy
Dlaczego: create_task opakowuje korutynę w Task i planuje ją współbieżnie w działającej pętli zdarzeń.
pas7Na czym polega błąd?
async def f():
return 7
async def main():
print(f())
asyncio.run(main())- ABrak await — drukuje obiekt coroutine✓ Poprawna odpowiedź
- BBrak asyncio.run
- Cf musi być sync
- Dmain nie jest awaitowane
Dlaczego: Bez await f() zwraca obiekt coroutine zamiast wartości, a interpreter wyświetla RuntimeWarning.
pas8Co zostanie wypisane?
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✓ Poprawna odpowiedź
- B6
- C0
- DSyntaxError
Dlaczego: gen daje 0, 1, 2, a async for iteruje je, sumując do 3.
pas9Co wymusza Semaphore(2)?
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()))- ANajwyżej 2 workery w bloku jednocześnie✓ Poprawna odpowiedź
- BDokładnie 2 uruchomienia łącznie
- CDwusekundowe opóźnienie
- DDwie próby ponowienia
Dlaczego: Semaphore(2) ogranicza liczbę jednoczesnych posiadaczy do dwóch; pozostali czekają na miejsce.
pas10Co zostanie wypisane?
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✓ Poprawna odpowiedź
- B2 1
- CNone None
- DZakleszczenie
Dlaczego: asyncio.Queue jest domyślnie FIFO, więc elementy wychodzą w kolejności włożenia.
pas11Kiedy asyncio nie pasuje?
- AObliczenia ograniczone CPU✓ Poprawna odpowiedź
- BWiele równoległych żądań sieciowych
- CLong-poll websockety
- DWolne zapytania DB przez async driver
Dlaczego: asyncio sprawdza się przy I/O; zadania CPU blokują pętlę i wymagają procesów lub executorów.
pas12Co jest wypisane na końcu?
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✓ Poprawna odpowiedź
- Btick
- CCancelledError
- DNic
Dlaczego: Anulowanie taska wstrzykuje CancelledError; await ponownie go rzuca, except obsługuje i wypisuje done.
pas13Co robi asyncio.shield(coro)?
- AChroni wewnętrzny task przed anulowaniem propagowanym przez shield✓ Poprawna odpowiedź
- BCicho łapie wszystkie wyjątki
- CWymusza synchroniczne wykonanie
- DPrzypina task do CPU
Dlaczego: shield opakowuje task, więc anulowanie awaitującego nie anuluje wewnętrznego — działa do końca.
pas14Dlaczego async with dla httpx.AsyncClient?
async def main():
async with httpx.AsyncClient() as client:
r = await client.get("https://api.example.com/x")
return r.status_code- AZapewnia poprawne zamknięcie puli połączeń✓ Poprawna odpowiedź
- BWymagane dla każdego await
- CWyłącza weryfikację TLS
- DCzyni żądania synchronicznymi
Dlaczego: Async context manager gwarantuje wywołanie aclose(), deterministycznie zwalniając połączenia.
pas15Różnica między httpx.AsyncClient a requests?
- Ahttpx wspiera async/await; requests jest tylko synchroniczny✓ Poprawna odpowiedź
- Brequests zawsze szybszy
- CIdentyczne API
- Dhttpx nie obsługuje POST
Dlaczego: httpx ma klienty sync i async z podobnym API; requests nie ma natywnego wsparcia asyncio.
pas16Kiedy kończy się async with TaskGroup?
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())- APo zakończeniu wszystkich tasków-dzieci✓ Poprawna odpowiedź
- BZaraz po utworzeniu tasków
- CTylko przy anulowaniu
- DPo 1 s timeoutu
Dlaczego: TaskGroup czeka na zakończenie wszystkich tasków; gdy jeden zawiedzie, pozostałe są anulowane.
pas17Do czego służy tu run_in_executor?
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()))- AUruchamia kod blokujący poza pętlą w wątku✓ Poprawna odpowiedź
- BPrzyspiesza korutyny
- CZastępuje asyncio.run
- DDomyślnie włącza pulę procesów
Dlaczego: run_in_executor przerzuca synchroniczne wywołanie do puli wątków/procesów, pętla pozostaje responsywna.
pas18Co wypisze ten kod?
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✓ Poprawna odpowiedź
- BTrue False
- CFalse True
- DFalse False
Dlaczego: create_task zwraca Task opakowujący korutynę; ponowne f() tworzy nowy obiekt coroutine.
pas19Jaka jest kolejność wyjścia?
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✓ Poprawna odpowiedź
- Bc / open / close
- Copen / close / c
- Dclose / c / open
Dlaczego: Kod przed yield wykonuje się przy wejściu, wartość trafia do as, kod po yield przy wyjściu.
pas20Co zostanie zaobserwowane?
async def f():
raise RuntimeError("oops")
async def main():
asyncio.create_task(f())
await asyncio.sleep(0.05)
print("ok")
asyncio.run(main())- AWypisuje ok i loguje ostrzeżenie o nieobsłużonym wyjątku✓ Poprawna odpowiedź
- BOd razu rzuca RuntimeError
- CZawiesza się
- DWypisuje "oops"
Dlaczego: Task fire-and-forget chowa wyjątek do GC, gdy asyncio loguje ostrzeżenie o nieobsłużonym wyjątku.
pas21Co zostanie wypisane?
async def gen():
yield 1
yield 2
async def main():
it = gen()
print(await anext(it))
print(await anext(it))
asyncio.run(main())- A1, potem 2✓ Poprawna odpowiedź
- B2, potem 1
- CStopAsyncIteration
- DDwa obiekty coroutine
Dlaczego: anext czeka na __anext__ async iteratora i zwraca kolejne wartości po kolei.
pas22Czym różnią się seq i par?
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 sekwencyjnie (~0.02 s); par współbieżnie (~0.01 s)✓ Poprawna odpowiedź
- BIdentyczne zachowanie
- Cpar sekwencyjny, seq współbieżny
- Dpar wymaga wątków
Dlaczego: Awaitowanie po kolei jest sekwencyjne; gather uruchamia oba współbieżnie i kończy w czasie najwolniejszego.
pas23Co zostanie wypisane?
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✓ Poprawna odpowiedź
- BNone
- CZawiesza się
- DTimeoutError
Dlaczego: Event.set() zwalnia wszystkich oczekujących, więc wait() kończy się i task zwraca "go".
pas24Co kontroluje timeout=2.0?
async def fetch():
async with httpx.AsyncClient(timeout=2.0) as c:
r = await c.get("https://slow.example")
return r.text- ADomyślny timeout żądania dla wszystkich etapów klienta✓ Poprawna odpowiedź
- BMaks. czas życia klienta
- CLiczbę prób
- DRozmiar puli połączeń
Dlaczego: httpx traktuje liczbowy timeout jako domyślny dla connect, read, write i pool dla każdego żądania.
pas25Różnica między coroutine, Task i Future?
- ACoroutine: wynik wywołania; Task: zaplanowana korutyna; Future: niskopoziomowy placeholder wyniku✓ Poprawna odpowiedź
- BWszystkie identyczne
- CFuture działa synchronicznie, Task w wątku
- DCoroutine w wątku, Task w procesie
Dlaczego: Task to podklasa Future, która napędza korutynę w pętli; Future to prymityw wyniku awaitable.
python-fastapi · FastAPI + httpx · 25
pf1Co zrobi FastAPI dla żądania GET /items/abc?
from fastapi import FastAPI
app = FastAPI()
@app.get('/items/{item_id}')
def read(item_id: int):
return {'id': item_id}- AZwraca 200 z id="abc"
- BZwraca 422 błąd walidacji✓ Poprawna odpowiedź
- CZwraca 404 not found
- DZgłasza ValueError
Dlaczego: Parametr jest typu int; "abc" nie da się skonwertować, więc FastAPI zwraca 422 z detalami walidacji.
pf2Które wywołanie używa obu domyślnych wartości?
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✓ Poprawna odpowiedź
- C/search?q=all
- D/search?limit=10
Dlaczego: Pominięcie obu parametrów zachowuje domyślne wartości q="all" i limit=10.
pf3Jaki status zwróci GET /u/-1?
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✓ Poprawna odpowiedź
- D500
Dlaczego: HTTPException(status_code=404) jest jawnie zgłaszany; FastAPI zwraca odpowiedź 404.
pf4Body { "name": "x" } zwraca jaki 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✓ Poprawna odpowiedź
- D500
Dlaczego: Field(min_length=2) odrzuca "x" (długość 1), Pydantic zgłasza błąd, FastAPI zwraca 422.
pf5Co klient otrzyma w JSON?
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"}✓ Poprawna odpowiedź
- C{"token":"secret"}
- DBłąd 500
Dlaczego: response_model filtruje wyjście do zadeklarowanych pól, odrzucając "token" przed serializacją.
pf6Jaki status domyślnie zwraca endpoint?
from fastapi import FastAPI, status
app = FastAPI()
@app.post('/items', status_code=status.HTTP_201_CREATED)
def create():
return {'ok': True}- A200
- B201✓ Poprawna odpowiedź
- C202
- D204
Dlaczego: Parametr status_code w dekoratorze nadpisuje domyślne 200, zwracając 201 Created.
pf7Co zwróci GET /i?q=hi?
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"}✓ Poprawna odpowiedź
- CBłąd 422
- D{"c":{"q":"hi"}}
Dlaczego: Depends(common) wywołuje common(q="hi") i wstrzykuje dict, który jest zwracany jako JSON.
pf8Kiedy wykonuje się blok finally?
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- APrzed endpointem
- BPo wysłaniu odpowiedzi✓ Poprawna odpowiedź
- CNigdy, tylko przy błędach
- DPrzy starcie aplikacji
Dlaczego: Zależności z yield uruchamiają kod sprzątający po dostarczeniu odpowiedzi, zwalniając zasoby.
pf9Dlaczego async def jest poprawne zamiast 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 nie może zwracać JSON
- Bawait wymaga funkcji async✓ Poprawna odpowiedź
- Chttpx jest tylko sync
- DFastAPI wymaga async
Dlaczego: await działa tylko w funkcjach async; httpx.AsyncClient wymaga await, więc endpoint musi być async.
pf10Kiedy log() działa względem odpowiedzi?
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}- APrzed wysłaniem odpowiedzi
- BPo wysłaniu odpowiedzi✓ Poprawna odpowiedź
- CRównolegle z odpowiedzią
- DPrzy następnym żądaniu
Dlaczego: BackgroundTasks uruchamia zadania po zwróceniu odpowiedzi klientowi.
pf11Co robi to middleware?
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- ABlokuje wszystkie żądania
- BDodaje nagłówek X-App do odpowiedzi✓ Poprawna odpowiedź
- CPrzekierowuje żądania
- DLoguje body żądań
Dlaczego: Middleware czeka na odpowiedź, dokleja nagłówek i zwraca ją klientowi.
pf12Które pochodzenie może wywołać API z przeglądarki?
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['https://x.com'],
allow_methods=['*'],
)- AKażde
- BTylko https://x.com✓ Poprawna odpowiedź
- CTylko same-origin
- DTylko http://x.com
Dlaczego: allow_origins to ścisła lista; tylko podane pochodzenie otrzyma nagłówki CORS.
pf13Jakiego content-type musi użyć klient?
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✓ Poprawna odpowiedź
- Dtext/plain
Dlaczego: UploadFile czyta z multipart/form-data; FastAPI potrzebuje pakietu python-multipart.
pf14Co należy wywołać przed send_text lub 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()✓ Poprawna odpowiedź
- Cwebsocket.open()
- DNic, opcjonalne
Dlaczego: Handshake WebSocket kończy się przy accept(); metody komunikacji wcześniej rzucą błąd.
pf15Po co używać StreamingResponse?
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')- AAuto-kompresja
- BWysyła body porcjami bez buforowania✓ Poprawna odpowiedź
- CWymagane dla JSON
- DDodaje CORS
Dlaczego: StreamingResponse iteruje generator i wysyła fragmenty od razu po ich wytworzeniu.
pf16Jaka jest pełna ścieżka 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✓ Poprawna odpowiedź
- C/users/v1
- D/list_users
Dlaczego: Prefix APIRouter jest dodawany; tags tylko grupują w OpenAPI, nie zmieniając ścieżki.
pf17Jak ma przyjść token?
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 ?token=
- BCookie token
- CNagłówek Authorization: Bearer✓ Poprawna odpowiedź
- DPole body token
Dlaczego: OAuth2PasswordBearer pobiera token z nagłówka Authorization w schemacie Bearer.
pf18Co TestClient uruchamia pod spodem?
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')- ARealne gniazdo sieciowe
- BWywołania ASGI przez httpx w procesie✓ Poprawna odpowiedź
- COsobny proces uvicorn
- DPrzeglądarkę Selenium
Dlaczego: TestClient używa httpx z transportem ASGI, wywołując aplikację bez otwierania portu.
pf19Co ten wzorzec zastępuje w nowym FastAPI?
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
print('startup')
yield
print('shutdown')
app = FastAPI(lifespan=lifespan)- ADekorator middleware
- B@app.on_event("startup"/"shutdown")✓ Poprawna odpowiedź
- CWstrzykiwanie zależności
- DBackgroundTasks
Dlaczego: Lifespan zastępuje przestarzałe on_event, łącząc logikę startu i wyłączania.
pf20Dla {"name":"ada"} jakie jest 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"✓ Poprawna odpowiedź
- CValidationError
- DNone
Dlaczego: field_validator zwraca przekształconą wartość; "ADA" zastępuje oryginalny wejściowy ciąg.
pf21Co dla {"name":"a","age":1}?
from pydantic import BaseModel, ConfigDict
class User(BaseModel):
model_config = ConfigDict(extra='forbid')
name: str- AAkceptuje, age ignorowane
- BValidationError✓ Poprawna odpowiedź
- Cage zapisane
- DCichy warning
Dlaczego: extra="forbid" sprawia, że Pydantic v2 odrzuca niezadeklarowane pola błędem walidacji.
pf22Co robi asyncio.gather z tymi żądaniami?
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}- ASekwencyjnie
- BRównolegle, czeka na obie✓ Poprawna odpowiedź
- CTworzy wątki OS
- DCachuje drugą odpowiedź
Dlaczego: gather planuje obie korutyny w pętli zdarzeń; czas to maks z dwóch, nie suma.
pf23Jak nazywa się ten wzorzec?
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- APod-zależności✓ Poprawna odpowiedź
- BŁańcuch middleware
- CZadania w tle
- DLifespan hooks
Dlaczego: admin zależy od auth, a route od admin — FastAPI rozwiązuje łańcuch od góry.
pf24Dlaczego sync def jest tu akceptowalne mimo blokowania?
from fastapi import FastAPI
import time
app = FastAPI()
@app.get('/work')
def work():
time.sleep(2)
return 'done'- AFastAPI ignoruje blokowanie
- BDziała w threadpool, nie w pętli✓ Poprawna odpowiedź
- Ctime.sleep nie blokuje
- DBlokuje pętlę fatalnie
Dlaczego: Sync endpointy lecą w threadpool anyio, więc blokujące wywołania nie zamrażają pętli.
pf25Dlaczego yield zamiast return dla sesji?
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 zakazany
- BBy zamknąć sesję po odpowiedzi✓ Poprawna odpowiedź
- Cyield jest szybsze
- DWymóg SQLAlchemy
Dlaczego: Yield pozwala FastAPI wykonać finally po odpowiedzi, gwarantując zamknięcie sesji nawet przy błędach.