Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kontrollstrukturen

1 Bedingungen

1.1 if, elif und else

a = 1
b = 2

if a > b:
    print('a ist größer als b')
elif a < b:  # = elseif bzw. else if in anderen Sprachen
    print('a ist kleiner als b')
else:
    print('a ist gleich b')

Häufig kann man direkte Vergleiche weglassen:

check = True
string = 'Text'

if check is True:
    print('Bedingung erfüllt.')

if len(string) != 0:
    print('String ist nicht leer.')

# Kürzer:
if check:
    print('Bedingung erfüllt.')

if string:
    print('String ist nicht leer.')

1.2 Shorthand

a = 1
b = 2

if a < b: print('a ist kleiner als b')

1.3 Ternary operators (conditional expressions)

Ein Ternary Operator (conditional expression) fasst eine einfache if-else-Abfrage in einer einzigen Zeile zusammen. Die Syntax lautet: wert_wenn_wahr if bedingung else wert_wenn_falsch. Das Ergebnis wird direkt einer Variable zugewiesen oder weiterverwendet. Sinnvoll ist diese Schreibweise, wenn der Ausdruck kurz und gut lesbar bleibt.

a = 1
b = 2

comment = 'a ist größer als b' if a > b else 'a ist kleiner als b'
print(comment)  # a ist kleiner als b

1.4 ShortHand Ternary

Python wertet logische Ausdrücke mit or lazy aus: Der rechte Operand wird nur dann betrachtet, wenn der linke falsy ist (also False, None, 0, '', [] usw.). Das lässt sich als kompakte Alternative zu einem Ternary Operator nutzen, um Fallback-Werte zu setzen.

Beispiel 1:

print( True or 'Some' )  # True

Beispiel 2:

print( False or 'Some' )  # Some

Beispiel 3:

output = None
msg = output or 'Keine Daten'
print(msg)  # Keine Daten

1.5 Verkettete Vergleiche

Python erlaubt mathematisch natürliche Vergleichsketten, die von links nach rechts ausgewertet werden:

x = 1.5

# Andere Sprachen:
if x > 1 and x < 2:
    print('x liegt zwischen 1 und 2')

# Python-Kurzform:
if 1 < x < 2:
    print('x liegt zwischen 1 und 2')

2 Switch-Case-Äquivalent für Python-Version < 3.10

Vor Python-Version 3.10 gibt es keine Switch-Case-Anweisung, sie muss simuliert werden:

def switcher(age):
    if age < 18:
        msg = 'Minderjährig'
    elif age < 67:
        msg = 'Volljährig'
    elif age in range(0, 150):
        msg = 'Rentner'
    else:
        msg = 'Fehler'

    return msg

print(switcher(50))  # Volljährig

3 Pattern Matching mit match-case (Python 3.10+)

Seit Python 3.10 gibt es strukturelles Pattern Matching mit match-case. Dies ist deutlich mächtiger als einfache Switch-Case-Statements aus anderen Sprachen.

3.1 Einfaches Matching (Literal Patterns)

def http_status(status):
    match status:
        case 200:
            return 'OK'
        case 404:
            return 'Nicht gefunden'
        case 500:
            return 'Interner Serverfehler'
        case _:  # Wildcard (Standard)
            return 'Unbekannter Status'

print(http_status(404))  # Nicht gefunden

3.2 Mehrere Werte (OR-Patterns)

def classify_http_status(status):
    match status:
        case 200 | 201 | 204:
            return 'Erfolgreich'
        case 400 | 401 | 403 | 404:
            return 'Client-Fehler'
        case 500 | 502 | 503:
            return 'Server-Fehler'
        case _:
            return 'Unbekannt'

print(classify_http_status(201))  # Erfolgreich

3.3 Guards (if-Bedingungen)

age = 50

match age:
    case _ if age < 0:
        msg = 'Ungültiges Alter'
    case _ if age < 18:
        msg = 'Minderjähriger'
    case _ if age < 67:
        msg = 'Erwachsener'
    case _ if age < 150:
        msg = 'Rentner'
    case _:
        msg = 'Ungültiges Alter'

print(msg)  # Erwachsener

3.4 Sequence Patterns (Listen, Tupel)

# Listen/Tupel matchen
point = (0, 5)

match point:
    case (0, 0):
        print('Ursprung')
    case (0, y):
        print(f'Auf y-Achse bei y={y}')
    case (x, 0):
        print(f'Auf x-Achse bei x={x}')
    case (x, y):
        print(f'Punkt auf ({x}, {y})')

# Ausgabe: Aus y-Achse bei y=5

Variable-length Patterns:

data = [1, 2, 3, 4, 5]

match data:
    case []:
        print('Leere Liste')
    case [x]:
        print(f'Einzelnes Element: {x}')
    case [x, y]:
        print(f'Zwei Elemente: {x}, {y}')
    case [first, *rest]:
        print(f'Erstes: {first}, Rest: {rest}')

# Ausgabe: Erstes: 1, Rest: [2, 3, 4, 5]

Exakte Länge mit Wildcard:

coordinates = (10, 20, 30)

match coordinates:
    case (x, y):
        print(f'2D: {x}, {y}')
    case (x, y, z):
        print(f'3D: {x}, {y}, {z}')
    case (x, y, z, _):
        print(f'4D+: Erste drei {x}, {y}, {z}')

# Ausgabe: 3D: 10, 20, 30

3.5 Mapping Patterns (Dictionaries)

user = {'name': 'Alice', 'age': 30, 'role': 'admin'}

match user:
    case {'role': 'admin', 'name': name}:
        print(f'Administrator: {name}')
    case {'role': 'user', 'name': name}:
        print(f'Normaler Benutzer: {name}')
    case {'name': name}:
        print(f'Benutzer ohne Rolle: {name}')

# Ausgabe: Administrator: Alice

Wichtig: Dictionaries matchen partial (zusätzliche Keys werden ignoriert):

data = {'type': 'point', 'x': 10, 'y': 20, 'color': 'red'}

match data:
    case {'type': 'point', 'x': x, 'y': y}:
        print(f'Punkt bei ({x}, {y})')
        # 'color' wird ignoriert

# Ausgabe: Punkt bei (10, 20)

3.6 Class Patterns (Strukturelles Matching)

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

@dataclass
class Circle:
    center: Point
    radius: int

shape = Circle(Point(0, 0), 5)

match shape:
    case Circle(center=Point(x=0, y=0), radius=r):
        print(f'Kreis im Ursprung mit Radius {r}')
    case Circle(center=Point(x=x, y=y), radius=r):
        print(f'Kreis bei ({x}, {y}) mit Radius {r}')

# Ausgabe: Kreis im Ursprung mit Radius 5

Kürzere Syntax:

match shape:
    case Circle(Point(0, 0), r):
        print(f'Kreis im Ursprung mit Radius {r}')
    case Circle(Point(x, y), r):
        print(f'Kreis bei ({x}, {y}) mit Radius {r}')

3.7 AS Patterns (Capture Whole + Parts)

Mit as kann man sowohl das Gesamtobjekt als auch Teile davon erfassen:

data = [1, 2, 3, 4]

match data:
    case [x, *rest] as full_list:
        print(f'Erstes: {x}')
        print(f'Rest: {rest}')
        print(f'Gesamte Liste: {full_list}')

# Ausgabe:
# Erstes: 1
# Rest: [2, 3, 4]
# Gesamte Liste: [1, 2, 3, 4]

3.8 Verschachtelte Patterns

command = ('move', {'x': 10, 'y': 20})

match command:
    case ('move', {'x': x, 'y': y}):
        print(f'Bewege zu ({x}, {y})')
    case ('resize', {'width': w, 'height': h}):
        print(f'Skaliere auf {w}x{h}')
    case ('rotate', {'angle': angle}):
        print(f'Drehe um {angle}°')

# Ausgabe: Bewege zu (10, 20)

3.9 Best Practices

✅ DO:

  • Nutze Pattern Matching für komplexe Datenstrukturen
  • Verwende Guards für zusätzliche Bedingungen
  • Ordne Patterns von spezifisch zu allgemein
  • Nutze _ als Wildcard/Default-Case

❌ DON’T:

  • Verwende nicht match für einfache if-elif-Ketten
  • Vermeide zu komplexe, verschachtelte Patterns

3.10 Pattern Matching vs. if-elif

Wann match verwenden:

# Gut für strukturelle Daten
match point:
    case (0, 0): return 'Ursprung'
    case (x, 0): return f'x-Achse: {x}'
    case (0, y): return f'y-Achse: {y}'
    case (x, y): return f'Punkt: ({x}, {y})'

Wann if-elif verwenden:

# Besser für einfache Vergleiche
if age < 18:
    return 'Minderjährig'
elif age < 65:
    return 'Erwachsen'
else:
    return 'Senior'

3.11 Zusammenfassung

Pattern-TypBeispielVerwendung
Literalcase 200:Exakter Wert
Wildcardcase _:Match alles (default)
Capturecase x:Wert in Variable speichern
ORcase 200 | 201 | 204:Mehrere Werte
Sequencecase [x, y, z]:Listen/Tupel mit fester Länge
Sequence (rest)case [first, *rest]:Variable Länge
Mappingcase {'key': value}:Dictionaries
Classcase Point(x, y):Objekte/Dataclasses
Guardcase x if x > 0:Zusätzliche Bedingung
AScase [x, *rest] as full:Ganzes + Teile erfassen

4 Schleifen

4.1 for-Schleifen

L = [0, 1, 2, 3]
count = len(L)

# von 0 bis count-1
for i in range(count):
    print(L[i], end=', ' if i < count-1 else '\n')  # 0, 1, 2, 3

# von 1 bis count-1
for i in range(1, count):
    print(L[i], end=', ' if i < count-1 else '\n')  # 1, 2, 3

# von 0 bis count-1 mit Schrittweite 2
for i in range(0, count, 2):
    print(L[i], end=', ' if i < count-2 else '\n')  # 0, 2

# von count-1 bis 0 (rückwärts)
for i in range(count-1, -1, -1):
    print(L[i], end=', ' if i != 0 else '\n')       # 3, 2, 1, 0
D = {'A': 1, 'B': 3, 'C': 7}

for key in D:
    print(key, end=' ')  # A, B, C

print('')

for key, value in D.items():
    print(f'{key}={value}', end=' ')  # A=1 B=3 C=7

Mit Zählervariable:

lst = ['A', 'B', 'C']

for i in range(len(lst)):
    print(lst[i])

# Kürzer:
for value in lst:
    print(value)

# Wird der Index benötigt:
for i, value in enumerate(lst):
    print(f'{i}: {value}')

Bildung eines Iterators mittels zip():

a = [1, 2, 3]
b = [4, 5, 6]

for i in range(len(a)):
    print(f'{a[i]} und {b[i]}')

# Besser:
for av, bv in zip(a, b):
    print(f'{av} und {bv}')

# Mit Index:
for i, (av, bv) in enumerate(zip(a, b)):
    print(f'{i}: {av} und {bv}')

4.2 while-Schleifen

Mit Zählbedingung:

i = 0
m = 3

while i <= m:
    print(i)
    i += 1

Mit Flag:

i = 0
m = 3
run = True

while run:
    print(i)
    if i == m: run = False
    i += 1

Endlosschleife mit break:

i = 0
m = 3

while True:
    print(i)
    if i == m: break
    i += 1

4.3 for-else und while-else

Der else-Block einer Schleife wird ausgeführt, wenn die Schleife ohne break beendet wurde, d. h. vollständig durchgelaufen ist.

# Suche nach einem Element
values = [1, 3, 5, 7, 9]

for v in values:
    if v == 4:
        print('Gefunden!')
        break
else:
    print('Nicht gefunden.')  # Wird ausgeführt, da kein break

# Ausgabe: Nicht gefunden.

Typischer Anwendungsfall: Prüfen, ob eine Bedingung in einer Schleife jemals erfüllt wurde, ohne eine Extra-Flag-Variable.

# Mit Flag (umständlicher):
found = False
for v in values:
    if v % 2 == 0:
        found = True
        break
if not found:
    print('Keine geraden Zahlen.')

# Kürzer mit for-else:
for v in values:
    if v % 2 == 0:
        break
else:
    print('Keine geraden Zahlen.')

Counter aus collections

Counter zählt Häufigkeiten von Elementen in einem Iterable und eignet sich gut als Alternative zu manuellen Zählschleifen.

from collections import Counter

words = ['apfel', 'birne', 'apfel', 'kirsche', 'birne', 'apfel']

# Manuell (umständlich):
counts = {}
for w in words:
    counts[w] = counts.get(w, 0) + 1

# Mit Counter:
counts = Counter(words)
print(counts)
# Counter({'apfel': 3, 'birne': 2, 'kirsche': 1})

# Häufigste Elemente
print(counts.most_common(2))  # [('apfel', 3), ('birne', 2)]

# Einzelne Abfrage
print(counts['apfel'])   # 3
print(counts['zitrone']) # 0  (kein KeyError!)

Counter lässt sich auch mit anderen Counter-Objekten addieren oder subtrahieren:

a = Counter(['x', 'y', 'x'])
b = Counter(['y', 'y', 'z'])

print(a + b)  # Counter({'y': 3, 'x': 2, 'z': 1})
print(a - b)  # Counter({'x': 2})  (nur positive Werte)