Python lernen — jede Frage, jede Antwort
Alle 125 Fragen auf 5 Stufen mit Codebeispielen, akzeptierten Antworten und ausführlichen Erklärungen. Kostenlos, ohne Anmeldung, vollständig indexiert.
Eine vollständige Python-Referenz: von grundlegenden Typen und Kontrollfluss über Dataclasses, Decorators und contextlib bis zu asyncio, FastAPI und Pydantic. Jeder Eintrag zeigt den lauffähigen Code, die richtige Antwort und die zugrunde liegende Regel.
python-basic · Grundlagen · 25
pb1Was gibt dieser Code aus?
x = 7
y = 2
print(x // y)- A3.5
- B3✓ Richtige Antwort
- C4
- D3.0
Warum: Der //-Operator führt Ganzzahldivision durch und liefert 3 bei zwei Ints.
pb2Welcher Bezeichner ist in Python NICHT gültig?
- A_value
- Bmy_var2
- C2nd_place✓ Richtige Antwort
- DCamelCase
Warum: Bezeichner dürfen nicht mit einer Ziffer beginnen; nur Buchstabe oder Unterstrich.
pb3Welcher Typ wird ausgegeben?
print(type(3 / 2))- A<class 'int'>
- B<class 'float'>✓ Richtige Antwort
- C<class 'number'>
- D<class 'double'>
Warum: Der /-Operator liefert in Python 3 immer ein float, auch bei Ints.
pb4Was gibt dieser Code aus?
s = " Hello "
print(s.strip().upper())- A HELLO
- BHELLO✓ Richtige Antwort
- CHello
- D Hello
Warum: .strip() entfernt umgebende Leerzeichen, dann wandelt .upper() in Großbuchstaben um.
pb5Was gibt dieses Slicing aus?
s = "python"
print(s[1:4])- Apyt
- Byth✓ Richtige Antwort
- Cytho
- Dthon
Warum: Der Slice s[1:4] nimmt Indizes 1, 2, 3 — das Ende ist exklusiv.
pb6Was gibt dieser f-String aus?
name = "Ada"
print(f"Hi, {name}!")- AHi, {name}!
- BHi, Ada!✓ Richtige Antwort
- CHi, "Ada"!
- DSyntaxError
Warum: F-Strings setzen den Wert von Ausdrücken in geschweiften Klammern ein.
pb7Was gibt dieser Code aus?
xs = [1, 2]
xs.append([3, 4])
print(len(xs))- A2
- B3✓ Richtige Antwort
- C4
- DTypeError
Warum: append fügt ein einzelnes Element (die innere Liste) hinzu — Länge wird 3.
pb8Was gibt dieser Code aus?
xs = [1, 2, 3]
xs.extend([4, 5])
print(xs)- A[1, 2, 3, [4, 5]]
- B[1, 2, 3, 4, 5]✓ Richtige Antwort
- C[4, 5, 1, 2, 3]
- D[1, 2, 3]
Warum: extend iteriert das Argument und hängt jedes Element einzeln an die Liste an.
pb9Was passiert beim Ausführen des Codes?
t = (1, 2, 3)
t[0] = 9
print(t)- AGibt (9, 2, 3) aus
- BGibt (1, 2, 3) aus
- CTypeError✓ Richtige Antwort
- DIndexError
Warum: Tupel sind unveränderlich; Zuweisung an einen Index löst TypeError aus.
pb10Was gibt dieser Code aus?
d = {"a": 1, "b": 2}
print(d.get("c", 0))- ANone
- BKeyError
- C0✓ Richtige Antwort
- D1
Warum: dict.get(key, default) liefert den Standardwert, wenn der Schlüssel fehlt.
pb11Was prüft der in-Operator bei einem dict?
d = {"x": 1}
print("x" in d)- AWertzugehörigkeit
- BSchlüsselzugehörigkeit✓ Richtige Antwort
- CPaarzugehörigkeit
- DImmer False
Warum: Bei dicts prüft der in-Operator, ob ein Schlüssel existiert, nicht Werte.
pb12Was gibt dieser Code aus?
s = {1, 2, 2, 3, 3, 3}
print(len(s))- A6
- B3✓ Richtige Antwort
- C2
- D1
Warum: Sets speichern nur eindeutige Elemente, Duplikate werden entfernt: {1, 2, 3}.
pb13Was gibt dieser Code aus?
vals = [0, "", None, [], "x"]
truthy = [v for v in vals if v]
print(len(truthy))- A5
- B4
- C1✓ Richtige Antwort
- D0
Warum: 0, "", None und [] sind falsy; nur "x" überlebt den Filter.
pb14Was gibt dieser Code aus?
x = 10
if x > 20:
print("A")
elif x > 5:
print("B")
else:
print("C")- AA
- BB✓ Richtige Antwort
- CC
- DBC
Warum: Nur der erste passende Zweig läuft; 10 > 5 ist wahr, also "B".
pb15Was gibt dieser Code aus?
total = 0
for i in range(1, 5):
total += i
print(total)- A15
- B10✓ Richtige Antwort
- C6
- D4
Warum: range(1, 5) liefert 1, 2, 3, 4 (Ende exklusiv); Summe ist 10.
pb16Welche Zeile wird zuerst ausgegeben?
names = ["a", "b", "c"]
for i, n in enumerate(names):
print(i, n)- A1 a
- B0 a✓ Richtige Antwort
- Ca 0
- D0 "a"
Warum: enumerate liefert Paare (Index, Wert), standardmäßig ab 0.
pb17Was gibt dieser Code aus?
a = [1, 2, 3]
b = ["x", "y"]
print(list(zip(a, b)))- A[(1, 'x'), (2, 'y'), (3, None)]
- B[(1, 'x'), (2, 'y')]✓ Richtige Antwort
- C[1, 'x', 2, 'y', 3]
- DFehler
Warum: zip stoppt am kürzesten Iterable; das dritte Element von a entfällt.
pb18Was gibt diese Comprehension aus?
squares = [x*x for x in range(4)]
print(squares)- A[1, 4, 9, 16]
- B[0, 1, 4, 9]✓ Richtige Antwort
- C[0, 1, 2, 3]
- D[1, 2, 4, 8]
Warum: range(4) liefert 0, 1, 2, 3; Quadrate ergeben [0, 1, 4, 9].
pb19Was gibt dieser Code aus?
def greet(name, greeting="Hi"):
return f"{greeting}, {name}"
print(greet("Sam"))- AHi, Sam✓ Richtige Antwort
- BSam, Hi
- CTypeError
- DHi, name
Warum: Standardargumente werden genutzt, wenn nicht übergeben; greeting ist "Hi".
pb20Was gibt dieser Code aus?
def total(*args, **kwargs):
return sum(args) + sum(kwargs.values())
print(total(1, 2, x=3, y=4))- A3
- B7
- C10✓ Richtige Antwort
- DTypeError
Warum: *args sammelt (1, 2), **kwargs {x:3, y:4}; Summen ergeben 3 + 7 = 10.
pb21Was gibt dieser Code aus?
def f():
pass
print(type(f()).__name__)- ANone
- BNoneType✓ Richtige Antwort
- Cfunction
- Dvoid
Warum: Eine Funktion ohne return liefert None; dessen Klasse heißt NoneType.
pb22Was gibt dieser Code aus?
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b, a is b)- ATrue True
- BTrue False✓ Richtige Antwort
- CFalse True
- DFalse False
Warum: == vergleicht Werte (gleich); is prüft Identität — verschiedene Objekte.
pb23Was gibt dieser Code aus?
print(isinstance(True, int))- ATrue✓ Richtige Antwort
- BFalse
- CTypeError
- DNone
Warum: In Python ist bool eine Unterklasse von int, daher ist isinstance(True, int) True.
pb24Was gibt dieser Code aus?
try:
x = int("abc")
except ValueError:
x = -1
print(x)- A0
- B-1✓ Richtige Antwort
- Cabc
- DValueError
Warum: int("abc") wirft ValueError, der gefangen wird und x auf -1 setzt.
pb25Was gibt dieser Code aus?
import math
print(math.sqrt(16))- A4
- B4.0✓ Richtige Antwort
- C16
- DImportError
Warum: math.sqrt liefert stets ein float; sqrt(16) gibt 4.0 aus, nicht 4.
python-medium · Mittel · 25
pm1Was gibt das aus?
class Dog:
species = 'canine'
def __init__(self, name):
self.name = name
a = Dog('Rex')
Dog.species = 'wolf'
print(a.species)- Acanine
- Bwolf✓ Richtige Antwort
- CRex
- DAttributeError
Warum: species ist ein Klassenattribut; eine Änderung wirkt auf Instanzen ohne eigene Überschreibung.
pm2Was gibt das aus?
class A:
def hi(self): return 'A'
class B(A):
def hi(self): return 'B' + super().hi()
print(B().hi())- AB
- BA
- CBA✓ Richtige Antwort
- DAB
Warum: B.hi liefert "B" plus super().hi() (A.hi -> "A"), also "BA".
pm3Was gibt das aus?
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✓ Richtige Antwort
- B212
- C<property>
- DTypeError
Warum: @property erlaubt f ohne Klammern; 100*9/5+32 ergibt 212.0 (Gleitkommadivision).
pm4Was gibt das aus?
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✓ Richtige Antwort
- B5 cls
- CTypeError
- D23 Math
Warum: @staticmethod hat keine impliziten Argumente; @classmethod erhält cls mit der Klasse.
pm5Was gibt das aus?
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✓ Richtige Antwort
- Bhi ann
- CHI ann
- DTypeError
Warum: Der Dekorator umschließt greet; "hi ann" wird in Großbuchstaben "HI ANN" umgewandelt.
pm6Wie ist die Ausgabereihenfolge?
class Open:
def __enter__(self):
print('in'); return self
def __exit__(self, *a):
print('out')
with Open():
print('mid')- Ain, mid, out✓ Richtige Antwort
- Bmid, in, out
- Cin, out, mid
- Dout, mid, in
Warum: Zuerst __enter__, dann der with-Block, schließlich __exit__ am Ende.
pm7Was gibt das aus?
def gen():
yield 1
yield 2
yield 3
g = gen()
print(next(g), next(g))- A1 2✓ Richtige Antwort
- B1 1
- C2 3
- D1 2 3
Warum: Jedes next() rückt den Generator zum nächsten yield vor und liefert 1, dann 2.
pm8Was gibt das aus?
try:
raise ValueError('a')
except ValueError:
print('v')
else:
print('e')
finally:
print('f')- Av dann f✓ Richtige Antwort
- Bv dann e dann f
- Ce dann f
- Dnur f
Warum: else läuft nur ohne Ausnahme; finally läuft immer.
pm9Was gibt das aus?
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]✓ Richtige Antwort
- B[0, 1]
- C[1, 2, 3]
- D[]
Warum: list() iteriert bis StopIteration; 1 und 2 werden geliefert, bevor i 2 erreicht.
pm10Was gibt das aus?
nums = [1, 2, 3, 4, 5]
print([x*x for x in nums if x % 2])- A[1, 9, 25]✓ Richtige Antwort
- B[1, 4, 9, 16, 25]
- C[4, 16]
- D[1, 3, 5]
Warum: Die Comprehension behält ungerade Zahlen und quadriert sie: 1, 9, 25.
pm11Was gibt das aus?
nums = [1, 2, 3, 4]
print(list(filter(lambda x: x > 2, nums)))- A[3, 4]✓ Richtige Antwort
- B[1, 2]
- C[2, 3, 4]
- D[True, True]
Warum: filter behält Elemente, bei denen die Lambda wahr ist; nur 3 und 4 sind > 2.
pm12Was gibt das aus?
from functools import partial
def power(base, exp): return base ** exp
square = partial(power, exp=2)
print(square(5))- A25✓ Richtige Antwort
- B10
- C32
- DTypeError
Warum: partial fixiert exp=2; square(5) berechnet 5**2, also 25.
pm13Was gibt das aus?
from pathlib import Path
p = Path('/tmp/data.txt')
print(p.suffix, p.stem)- A.txt data✓ Richtige Antwort
- Btxt data
- C.txt /tmp/data
- Ddata .txt
Warum: Path.suffix enthält den Punkt (".txt"); Path.stem ist der Name ohne Endung ("data").
pm14Was gibt das aus?
from collections import Counter
print(Counter('mississippi').most_common(2))- A[('i', 4), ('s', 4)]✓ Richtige Antwort
- B[('i', 4), ('m', 1)]
- C[('s', 4), ('i', 4)]
- D[('p', 2), ('m', 1)]
Warum: "mississippi" hat vier i und vier s; most_common(2) liefert diese beiden Paare.
pm15Was ist die erste ausgegebene Zeile?
for i, v in enumerate(['a', 'b', 'c'], start=10):
print(i, v)- A10 a✓ Richtige Antwort
- B0 a
- C1 a
- D10 c
Warum: enumerate(start=10) beginnt bei 10, also ist das erste Paar (10, "a").
pm16Was gibt das aus?
def classify(x):
match x:
case 0: return 'zero'
case int(): return 'int'
case _: return 'other'
print(classify(5))- Aint✓ Richtige Antwort
- Bzero
- Cother
- DSyntaxError
Warum: 5 ist nicht 0, passt aber auf int(), daher wird "int" vor dem Wildcard zurückgegeben.
pm17Was gibt das aus?
pi = 3.14159
print(f'{pi:.2f}')- A3.14✓ Richtige Antwort
- B3.142
- C3.14159
- D3.1
Warum: Der Formatspezifizierer .2f rundet auf zwei Nachkommastellen.
pm18Was gibt das aus?
import copy
a = [[1, 2], [3, 4]]
b = copy.copy(a)
b[0].append(9)
print(a)- A[[1, 2, 9], [3, 4]]✓ Richtige Antwort
- B[[1, 2], [3, 4]]
- C[[1, 2], [3, 4, 9]]
- D[[1, 2, 9], [3, 4, 9]]
Warum: copy.copy ist flach; innere Listen werden geteilt, b[0] zu ändern betrifft auch a[0].
pm19Was gibt das aus?
print('a,b,c,d'.split(',', maxsplit=2))- A['a', 'b', 'c,d']✓ Richtige Antwort
- B['a', 'b', 'c', 'd']
- C['a,b', 'c', 'd']
- D['a', 'b,c,d']
Warum: maxsplit=2 ergibt drei Teile; der Rest "c,d" bleibt als ein Element.
pm20Was gibt das aus?
a = {'x': 1, 'y': 2}
b = {'y': 9, 'z': 3}
print(a | b)- A{'x': 1, 'y': 9, 'z': 3}✓ Richtige Antwort
- B{'x': 1, 'y': 2, 'z': 3}
- C{'y': 9, 'z': 3}
- DTypeError
Warum: Der |-Operator vereint Dicts; bei Konflikten gewinnt rechts, daher y=9.
pm21Was gibt das aus?
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
print(sorted(pairs, key=lambda p: p[1]))- A[(3, 'a'), (1, 'b'), (2, 'c')]✓ Richtige Antwort
- B[(1, 'b'), (2, 'c'), (3, 'a')]
- C[(1, 'b'), (3, 'a'), (2, 'c')]
- D[(2, 'c'), (1, 'b'), (3, 'a')]
Warum: Der Schlüssel nimmt das zweite Tupelelement und sortiert alphabetisch.
pm22Was ist die zweite ausgegebene Zeile?
def add(x, items=[]):
items.append(x)
return items
print(add(1))
print(add(2))- A[1, 2]✓ Richtige Antwort
- B[2]
- C[1]
- D[2, 1]
Warum: Veränderliche Defaultargumente werden geteilt; dieselbe Liste sammelt 1 und dann 2.
pm23Was gibt das aus?
from collections import defaultdict
d = defaultdict(int)
for c in 'abca':
d[c] += 1
print(dict(d))- A{'a': 2, 'b': 1, 'c': 1}✓ Richtige Antwort
- B{'a': 1, 'b': 1, 'c': 1}
- CKeyError
- D{'a': 2}
Warum: defaultdict(int) legt fehlende Schlüssel mit 0 an; "abca" ergibt a=2, b=1, c=1.
pm24Was gibt das aus?
from functools import reduce
print(reduce(lambda a, b: a + b, [1, 2, 3, 4], 10))- A20✓ Richtige Antwort
- B10
- C24
- D14
Warum: reduce startet bei 10 und addiert 1+2+3+4=10, insgesamt 20.
pm25Was gibt das aus?
from collections import deque
d = deque([1, 2, 3])
d.appendleft(0)
d.append(4)
print(list(d))- A[0, 1, 2, 3, 4]✓ Richtige Antwort
- B[1, 2, 3, 0, 4]
- C[4, 0, 1, 2, 3]
- D[0, 4, 1, 2, 3]
Warum: appendleft fügt 0 vorne ein; append hängt 4 hinten an, ergibt [0, 1, 2, 3, 4].
python-advanced · Fortgeschritten · 25
pa1Type-checkt es und was wird ausgegeben?
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()))- ANein, En erbt nicht Greeter
- BJa, gibt HELLO aus✓ Richtige Antwort
- CJa, gibt hello aus
- DTypeError zur Laufzeit
Warum: Protocol nutzt strukturelles Typing: jede Klasse mit passenden Methoden erfüllt es ohne explizite Vererbung.
pa2Was passiert mit dieser 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 bei append
- BGibt [] aus
- CGibt ['x'] aus✓ Richtige Antwort
- DTypeError bei Konstruktion
Warum: frozen=True blockiert Neuzuweisung, aber referenzierte mutable Objekte können dennoch in-place geändert werden.
pa3Was gibt fmt(True) aus?
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✓ Richtige Antwort
- Cbool:True
- DTypeError
Warum: bool ist Subklasse von int, daher löst singledispatch True über die MRO zur int-Implementierung auf.
pa4Was garantiert Pythons GIL?
- AParallele CPU-Ausführung von Threads
- BNur ein Thread führt Bytecode gleichzeitig aus✓ Richtige Antwort
- CThread-sicheren Benutzercode
- DSchnelleres I/O als asyncio
Warum: Der GIL serialisiert Bytecode-Ausführung auf einen Thread, verhindert CPU-Parallelismus, macht Code aber nicht thread-sicher.
pa5Was wird ausgegeben?
from itertools import accumulate
import operator
nums = [1, 2, 3, 4]
print(list(accumulate(nums, operator.mul)))- A[1, 2, 6, 24]✓ Richtige Antwort
- B[1, 3, 6, 10]
- C[24]
- D[1, 2, 3, 4]
Warum: accumulate liefert laufende Ergebnisse: 1, 1*2, 1*2*3, 1*2*3*4 mit dem angegebenen Operator.
pa6Was passiert?
class C:
__slots__ = ('x',)
c = C()
c.x = 1
c.y = 2
print(c.x, c.y)- AGibt 1 2 aus
- BAttributeError bei c.y = 2✓ Richtige Antwort
- CTypeError bei Klassendefinition
- DGibt 1 None aus
Warum: __slots__ deaktiviert das Instanz-__dict__, daher löst das Setzen unbekannter Attribute AttributeError aus.
pa7Ist das gültig und was wird ausgegeben?
from typing import TypedDict, NotRequired
class User(TypedDict):
name: str
age: NotRequired[int]
u: User = {'name': 'Ada'}
print(u.get('age', 0))- ATypfehler: age fehlt
- BGültig, gibt 0 aus✓ Richtige Antwort
- CGültig, gibt None aus
- DLaufzeit-KeyError
Warum: NotRequired markiert den Schlüssel als optional, age weglassen ist gültig; .get liefert den Standard 0.
pa8Warum hier 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__)- AUm Dateien parallel zu öffnen
- BUm dynamisch viele Context Manager zu verwalten✓ Richtige Antwort
- CUm IOError zu unterdrücken
- DErsetzt try/except
Warum: ExitStack erlaubt das Betreten beliebig vieler Context Manager zur Laufzeit mit garantiertem korrekten Verlassen.
pa9Was gibt print aus?
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✓ Richtige Antwort
- C0
- DAttributeError
Warum: __set__ speichert 5*2 in _x; __get__ liest _x und gibt 10 zurück.
pa10Was wird ausgegeben?
from enum import StrEnum, auto
class Color(StrEnum):
RED = auto()
BLUE = auto()
print(Color.RED == 'red', Color.RED.value)- AFalse 1
- BTrue red✓ Richtige Antwort
- CTrue RED
- DFalse red
Warum: StrEnum.auto() erzeugt den kleingeschriebenen Namen; StrEnum-Mitglieder sind gleich ihrem Stringwert.
pa11Was erzeugt 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])]✓ Richtige Antwort
- C[(1,4),(2,2)]
- D[(1,[1,1,1,1,1,1])]
Warum: groupby gruppiert nur aufeinanderfolgende gleiche Elemente; nicht-benachbarte Läufe bilden separate Gruppen.
pa12Was wird ausgegeben?
import weakref
class Node: pass
n = Node()
r = weakref.ref(n)
print(r() is n)
del n
print(r())- ATrue dann None✓ Richtige Antwort
- BTrue dann <Node object>
- CFalse dann None
- DReferenceError
Warum: Ein weakref hält das Objekt nicht am Leben; nach Löschen der starken Referenz liefert der weakref None.
pa13Was ist die Ausgabe?
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✓ Richtige Antwort
- B3
- CTypeError
- DBox[int]
Warum: Generic[T] erlaubt parametrisches Typing; zur Laufzeit werden Typen gelöscht, 3 + 1 ergibt 4.
pa14Welche Aussage zu pickle vs json ist WAHR?
- Ajson serialisiert beliebige Python-Objekte
- Bpickle ist sicher aus unsicheren Quellen
- Cpickle kann beim Laden beliebigen Code ausführen✓ Richtige Antwort
- Djson bewahrt tuple vs list
Warum: pickle.load kann via manipulierter Daten Code ausführen; niemals Untrusted-Pickles laden. json ist sicher.
pa15Wie oft wird "compute" ausgegeben?
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✓ Richtige Antwort
- C2
- DFehler: benötigt __slots__
Warum: cached_property berechnet einmal pro Instanz und speichert in __dict__; Folgezugriffe überspringen die Berechnung.
pa16Was gibt das aus?
ba = bytearray(b'hello')
mv = memoryview(ba)
mv[0] = ord('H')
print(ba)- Abytearray(b'hello')
- Bbytearray(b'Hello')✓ Richtige Antwort
- CTypeError: bytes unveränderlich
- DBufferError
Warum: memoryview teilt den Puffer des bytearray (veränderlich); Schreiben verändert das Original direkt.
pa17Was gibt re.findall zurück?
import re
text = 'a1 b22 c333'
print(re.findall(r'\d+', text))- A['1', '22', '333']✓ Richtige Antwort
- BIterator über Match-Objekte
- C['a1', 'b22', 'c333']
- D[1, 22, 333]
Warum: findall liefert eine Liste von Strings, finditer einen Iterator über Match-Objekte.
pa18Was bewirkt assert_never hier?
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))- AWirft immer zur Laufzeit
- BStatische Vollständigkeitsprüfung; Fehler bei fehlenden Fällen✓ Richtige Antwort
- CUnterdrückt Warnungen
- DBehauptet shape None
Warum: assert_never signalisiert dem Type-Checker unerreichbaren Code; ein vergessener Fall verursacht einen Typfehler.
pa19Beste Wahl für CPU-gebundene Parallelität in CPython?
- Athreading
- Basyncio
- Cmultiprocessing✓ Richtige Antwort
- Dconcurrent.futures.ThreadPoolExecutor
Warum: multiprocessing startet separate Prozesse mit eigenem GIL und erreicht echte CPU-Parallelität.
pa20Was wird ausgegeben?
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✓ Richtige Antwort
- BAttributeError
- CNone
- DTypeError: Metaklassen-Konflikt
Warum: Die Metaklasse fügt greeting vor der Klassenerstellung ein, daher ist A.greeting "hi".
pa21Was ist 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✓ Richtige Antwort
- Cy-axis:0
- Dother
Warum: Muster werden von oben geprüft; (1,0) passt nicht zu (0,0), passt zu (x,0) mit x=1, liefert "x-axis:1".
pa22Warum ContextVar statt einer globalen?
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())- ASchneller als global
- BPro Task/Coroutine isoliert ohne explizite Übergabe✓ Richtige Antwort
- CThread-sicherer Lock-Ersatz
- DErfordert von asyncio.run
Warum: ContextVar bindet Werte an den aktuellen Kontext (Task); parallele Tasks sehen unabhängige Werte ohne Argumentdurchreichen.
pa23Was bewahrt 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- ANur den Rückgabetyp
- BDie vollständige Parametersignatur✓ Richtige Antwort
- CDie Laufzeitleistung
- DDen Funktionsnamen
Warum: ParamSpec erfasst positionale und Schlüsselwort-Parameter, damit Dekoratoren sie typgetreu weiterreichen.
pa24Was gibt das aus?
from itertools import islice, count
print(list(islice(count(10, 2), 2, 5)))- A[14, 16, 18]✓ Richtige Antwort
- B[10, 12, 14]
- C[12, 14, 16, 18]
- D[2, 3, 4]
Warum: count(10,2) liefert 10,12,14,16,18,...; islice nimmt Indizes 2,3,4 → 14,16,18.
pa25Warum Self statt "Builder" als Rückgabetyp?
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 ist zur Laufzeit schneller
- BSelf bewahrt den Subklassen-Typ für Fluent-Chaining✓ Richtige Antwort
- CSelf verbietet Vererbung
- DSie sind äquivalent
Warum: Self bezeichnet den tatsächlichen Empfängertyp; SubBuilder().add("x") wird als SubBuilder typisiert und erlaubt subklassenbewusstes Chaining.
python-async · Async (asyncio) · 25
pas1Was gibt dieser Code aus?
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]✓ Richtige Antwort
- B[2, 4, 6]
- C[1, 2, 3]
- DEin Coroutine-Objekt
Warum: gather bewahrt die Übergabe-Reihenfolge, daher entspricht das Ergebnis f(3), f(1), f(2) unabhängig von der Laufzeit.
pas2Was wird ausgegeben?
async def greet():
return "hi"
result = greet()
print(type(result).__name__)- Acoroutine✓ Richtige Antwort
- Bstr
- Cfunction
- DTask
Warum: Der Aufruf einer async def-Funktion liefert ein Coroutine-Objekt; der Körper läuft erst beim Await oder Scheduling.
pas3Wie lange dauert es ungefähr?
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 Sekunden✓ Richtige Antwort
- B~1 Sekunde
- C~0 Sekunden
- DWirft sofort
Warum: time.sleep blockiert den Event Loop, daher laufen die drei Coroutinen seriell statt nebenläufig.
pas4Was wird ausgegeben?
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']✓ Richtige Antwort
- BWirft ValueError
- C['NoneType', 'NoneType']
- D['Exception', 'Exception']
Warum: Mit return_exceptions=True liefert gather Ausnahme-Instanzen, statt sie zu werfen.
pas5Was passiert hier?
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())- AGibt "timeout" aus✓ Richtige Antwort
- BGibt 1 zurück
- CHängt 5 s
- DWirft ValueError
Warum: wait_for bricht die innere Coroutine beim Timeout ab und wirft asyncio.TimeoutError.
pas6Was macht asyncio.create_task?
- APlant eine Coroutine im Loop und liefert eine Task✓ Richtige Antwort
- BFührt die Coroutine aus und blockiert
- CErstellt einen neuen Event Loop
- DStartet einen OS-Thread
Warum: create_task verpackt eine Coroutine in eine Task und plant sie nebenläufig im laufenden Loop.
pas7Wo liegt der Fehler?
async def f():
return 7
async def main():
print(f())
asyncio.run(main())- AFehlendes await — gibt Coroutine-Objekt aus✓ Richtige Antwort
- Basyncio.run fehlt
- Cf muss sync sein
- Dmain wird nicht erwartet
Warum: Ohne await liefert f() ein Coroutine-Objekt statt des Werts und es kommt ein RuntimeWarning.
pas8Was wird ausgegeben?
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✓ Richtige Antwort
- B6
- C0
- DSyntaxError
Warum: gen liefert 0, 1, 2 und async for iteriert sie, Summe 3.
pas9Was erzwingt 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()))- AHöchstens 2 Worker gleichzeitig im Block✓ Richtige Antwort
- BGenau 2 Ausführungen insgesamt
- C2-Sekunden-Verzögerung
- DZwei Wiederholungen
Warum: Semaphore(2) begrenzt gleichzeitige Halter auf zwei; weitere warten auf einen Platz.
pas10Was wird ausgegeben?
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✓ Richtige Antwort
- B2 1
- CNone None
- DDeadlock
Warum: asyncio.Queue ist standardmäßig FIFO, Elemente kommen in Einfügereihenfolge heraus.
pas11Wann passt asyncio schlecht?
- ACPU-intensive Berechnungen✓ Richtige Antwort
- BViele parallele Netzwerkanfragen
- CLong-Poll-Websockets
- DLangsame DB-Abfragen via Async-Treiber
Warum: asyncio glänzt bei I/O; CPU-Tasks blockieren den Loop und brauchen Prozesse oder Executors.
pas12Was wird zuletzt ausgegeben?
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✓ Richtige Antwort
- Btick
- CCancelledError
- DNichts
Warum: Cancel injiziert CancelledError; Await wirft erneut, except behandelt und gibt done aus.
pas13Was macht asyncio.shield(coro)?
- ASchützt die innere Task vor Abbruch über das Shield✓ Richtige Antwort
- BSchluckt alle Ausnahmen
- CErzwingt synchrone Ausführung
- DPinnt Task an eine CPU
Warum: shield schützt die innere Task vor Abbruch des Awaiters; sie läuft normal zu Ende.
pas14Warum async with für httpx.AsyncClient?
async def main():
async with httpx.AsyncClient() as client:
r = await client.get("https://api.example.com/x")
return r.status_code- ASchließt den Verbindungspool korrekt✓ Richtige Antwort
- BPflicht für jedes await
- CDeaktiviert TLS-Prüfung
- DMacht Anfragen synchron
Warum: Der Context Manager garantiert aclose() und gibt den Verbindungspool sauber frei.
pas15Unterschied httpx.AsyncClient und requests?
- Ahttpx unterstützt async/await; requests ist nur synchron✓ Richtige Antwort
- Brequests ist immer schneller
- CIdentische APIs
- Dhttpx kann kein POST
Warum: httpx bietet Sync- und Async-Clients; requests hat keine native asyncio-Unterstützung.
pas16Wann verlässt 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())- AWenn alle Kindtasks fertig sind✓ Richtige Antwort
- BDirekt nach Erstellung
- CNur beim Abbruch
- DNach 1 s Timeout
Warum: TaskGroup wartet auf alle Kindtasks; bei Fehler werden die übrigen abgebrochen.
pas17Wofür dient run_in_executor hier?
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()))- AFührt blockierenden Code in einem Thread außerhalb des Loops aus✓ Richtige Antwort
- BBeschleunigt Coroutinen
- CErsetzt asyncio.run
- DAktiviert Prozess-Pool
Warum: run_in_executor lagert blockierende Aufrufe in einen Pool aus, der Loop bleibt reaktiv.
pas18Was gibt das aus?
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✓ Richtige Antwort
- BTrue False
- CFalse True
- DFalse False
Warum: create_task liefert eine Task; ein erneutes f() erzeugt eine neue Coroutine.
pas19Wie ist die Ausgabereihenfolge?
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✓ Richtige Antwort
- Bc / open / close
- Copen / close / c
- Dclose / c / open
Warum: Code vor yield läuft beim Eintritt, der Wert geht an as, Code nach yield beim Austritt.
pas20Was beobachtet man?
async def f():
raise RuntimeError("oops")
async def main():
asyncio.create_task(f())
await asyncio.sleep(0.05)
print("ok")
asyncio.run(main())- AGibt ok aus und protokolliert nicht abgerufene Exception✓ Richtige Antwort
- BWirft sofort RuntimeError
- CHängt ewig
- DGibt "oops" aus
Warum: Eine Fire-and-Forget-Task schluckt die Ausnahme bis zum GC; asyncio loggt dann eine Warnung.
pas21Was wird ausgegeben?
async def gen():
yield 1
yield 2
async def main():
it = gen()
print(await anext(it))
print(await anext(it))
asyncio.run(main())- A1 dann 2✓ Richtige Antwort
- B2 dann 1
- CStopAsyncIteration
- DZwei Coroutine-Objekte
Warum: anext erwartet __anext__ des Async-Iterators und liefert jeden Wert der Reihe nach.
pas22Wie unterscheiden sich seq und 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 sequentiell (~0.02 s); par nebenläufig (~0.01 s)✓ Richtige Antwort
- BIdentisches Verhalten
- Cpar sequentiell, seq nebenläufig
- Dpar benötigt Threads
Warum: Nacheinander awaiten ist seriell; gather läuft nebenläufig, Dauer des Langsamsten.
pas23Was wird ausgegeben?
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✓ Richtige Antwort
- BNone
- CHängt ewig
- DTimeoutError
Warum: Event.set() weckt alle Wartenden, wait() endet und die Task liefert "go".
pas24Was steuert 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- AStandard-Timeout pro Anfrage für diesen Client✓ Richtige Antwort
- BMaximale Client-Lebensdauer
- CWiederholungsanzahl
- DVerbindungspool-Größe
Warum: httpx wendet den numerischen Timeout auf connect, read, write und pool jeder Anfrage an.
pas25Unterschied Coroutine, Task und Future?
- ACoroutine: Aufrufergebnis; Task: geplante Coroutine; Future: Low-Level-Platzhalter✓ Richtige Antwort
- BAlle drei identisch
- CFuture synchron, Task im Thread
- DCoroutine im Thread, Task im Prozess
Warum: Task ist eine Future-Unterklasse, die eine Coroutine antreibt; Future ist das awaitable Ergebnis-Primitiv.
python-fastapi · FastAPI + httpx · 25
pf1Was macht FastAPI bei GET /items/abc?
from fastapi import FastAPI
app = FastAPI()
@app.get('/items/{item_id}')
def read(item_id: int):
return {'id': item_id}- AGibt 200 mit id="abc" zurück
- BGibt 422 Validierungsfehler zurück✓ Richtige Antwort
- CGibt 404 not found zurück
- DWirft ValueError
Warum: Der Pfadparameter ist int; "abc" ist nicht konvertierbar, daher liefert FastAPI 422 mit Details.
pf2Welcher Aufruf nutzt beide Standardwerte?
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✓ Richtige Antwort
- C/search?q=all
- D/search?limit=10
Warum: Wenn beide Parameter fehlen, gelten die Defaults q="all" und limit=10.
pf3Welchen HTTP-Status liefert 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✓ Richtige Antwort
- D500
Warum: HTTPException(status_code=404) wird ausgelöst; FastAPI antwortet mit 404.
pf4Welchen Status liefert body { "name": "x" }?
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✓ Richtige Antwort
- D500
Warum: Field(min_length=2) lehnt "x" (Länge 1) ab; Pydantic schlägt fehl, FastAPI liefert 422.
pf5Was erhält der Client im 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"}✓ Richtige Antwort
- C{"token":"secret"}
- DFehler 500
Warum: response_model filtert die Ausgabe auf deklarierte Felder; "token" wird vor der Serialisierung entfernt.
pf6Welchen Statuscode liefert dieser Endpoint?
from fastapi import FastAPI, status
app = FastAPI()
@app.post('/items', status_code=status.HTTP_201_CREATED)
def create():
return {'ok': True}- A200
- B201✓ Richtige Antwort
- C202
- D204
Warum: Der status_code-Parameter überschreibt das Standard-200 und liefert 201 Created.
pf7Was liefert 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"}✓ Richtige Antwort
- CFehler 422
- D{"c":{"q":"hi"}}
Warum: Depends(common) ruft common(q="hi") auf und injiziert das dict, das als JSON zurückkommt.
pf8Wann läuft der finally-Block?
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- AVor dem Endpoint
- BNach dem Senden der Antwort✓ Richtige Antwort
- CNie, nur bei Fehlern
- DBeim App-Start
Warum: yield-Dependencies räumen nach dem Senden der Antwort auf und geben Ressourcen frei.
pf9Warum async def statt 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 kann kein JSON liefern
- Bawait braucht async-Funktion✓ Richtige Antwort
- Chttpx ist nur sync
- DFastAPI verlangt async
Warum: await ist nur in async-Funktionen erlaubt; httpx.AsyncClient muss awaited werden.
pf10Wann läuft log() relativ zur Antwort?
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}- AVor dem Senden
- BNach dem Senden✓ Richtige Antwort
- CParallel zur Antwort
- DErst beim nächsten Request
Warum: BackgroundTasks führt Aufgaben aus, nachdem die Antwort gesendet wurde.
pf11Was macht diese 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- ABlockiert alle Requests
- BFügt jeder Antwort X-App hinzu✓ Richtige Antwort
- CLeitet alle um
- DLoggt Request-Bodies
Warum: Die Middleware wartet auf die Antwort, fügt den Header an und gibt sie zurück.
pf12Welcher Origin darf diese API aus dem Browser aufrufen?
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['https://x.com'],
allow_methods=['*'],
)- AJede
- BNur https://x.com✓ Richtige Antwort
- CNur gleicher Origin
- DNur http://x.com
Warum: allow_origins ist eine strikte Liste; nur dieser Origin erhält CORS-Header.
pf13Welchen Content-Type muss der Client nutzen?
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✓ Richtige Antwort
- Dtext/plain
Warum: UploadFile liest aus multipart/form-data; FastAPI benötigt python-multipart.
pf14Was muss vor send_text/receive_text aufgerufen werden?
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()✓ Richtige Antwort
- Cwebsocket.open()
- DNichts, optional
Warum: Der WebSocket-Handshake endet mit accept(); davor schlagen die Methoden fehl.
pf15Warum 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-Kompression
- BSendet Body inkrementell ohne Pufferung✓ Richtige Antwort
- CFür JSON nötig
- DFügt CORS hinzu
Warum: StreamingResponse iteriert einen Generator und sendet Chunks sofort.
pf16Wie lautet der volle Pfad von 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✓ Richtige Antwort
- C/users/v1
- D/list_users
Warum: Der prefix wird vorangestellt; tags gruppiert nur in OpenAPI.
pf17Wie kommt das Token an?
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
- CHeader Authorization: Bearer✓ Richtige Antwort
- DBody-Feld token
Warum: OAuth2PasswordBearer liest das Token aus dem Authorization-Header (Bearer).
pf18Was nutzt TestClient intern?
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')- AEchten Netzwerksocket
- BIn-Process-ASGI-Aufrufe via httpx✓ Richtige Antwort
- CSeparaten uvicorn-Prozess
- DSelenium
Warum: TestClient nutzt httpx mit ASGI-Transport und ruft die App direkt ohne Port auf.
pf19Was ersetzt dieses Muster im modernen 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-Dekorator
- B@app.on_event("startup"/"shutdown")✓ Richtige Antwort
- CDependency Injection
- DBackgroundTasks
Warum: Lifespan ersetzt die veralteten on_event-Handler und vereint Start/Stop.
pf20Was ist User().name bei {"name":"ada"}?
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"✓ Richtige Antwort
- CValidationError
- DNone
Warum: field_validator liefert den transformierten Wert; "ADA" ersetzt die Eingabe.
pf21Was passiert bei {"name":"a","age":1}?
from pydantic import BaseModel, ConfigDict
class User(BaseModel):
model_config = ConfigDict(extra='forbid')
name: str- AAkzeptiert, age ignoriert
- BValidationError✓ Richtige Antwort
- Cage gespeichert
- DStille Warnung
Warum: extra="forbid" lässt Pydantic v2 unbekannte Felder mit Fehler ablehnen.
pf22Was bewirkt asyncio.gather für die zwei 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}- ANacheinander
- BNebenläufig, wartet auf beide✓ Richtige Antwort
- CErzeugt OS-Threads
- DCacht die 2.
Warum: gather plant beide Coroutines im Event-Loop; Gesamtzeit ist das Maximum, nicht die Summe.
pf23Wie heißt dieses Muster?
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✓ Richtige Antwort
- BMiddleware-Kette
- CHintergrundaufgaben
- DLifespan-Hooks
Warum: admin hängt von auth ab und die Route von admin — FastAPI löst die Kette auf.
pf24Warum ist sync def hier trotz Blockierens akzeptabel?
from fastapi import FastAPI
import time
app = FastAPI()
@app.get('/work')
def work():
time.sleep(2)
return 'done'- AFastAPI ignoriert Blockaden
- BLäuft in einem Threadpool, nicht im Loop✓ Richtige Antwort
- Ctime.sleep blockiert nicht
- DBlockiert den Loop fatal
Warum: Sync-Endpoints laufen im anyio-Threadpool und blockieren den Loop nicht.
pf25Warum yield statt return für die Session?
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 verboten
- BUm die Session nach der Antwort zu schließen✓ Richtige Antwort
- Cyield ist schneller
- DSQLAlchemy verlangt es
Warum: Yield lässt FastAPI den finally-Block nach der Antwort ausführen und schließt die Session sicher.