02 Code-Qualität in der Praxis: Von funktionierendem Code zu professioneller Software
October 2025 (13356 Words, 75 Minutes)
1. Einleitung: Wenn funktionierender Code nicht ausreicht
Sie haben Ihre Road Profile Viewer Anwendung gebaut. Die Visualisierung ist schön, der Kamerastrahl schneidet perfekt mit dem Straßenprofil, und wenn Sie auf “Run” klicken, funktioniert alles. Herzlichen Glückwunsch! 🎉
Aber dann… pushen Sie Ihren Code auf GitHub, öffnen einen Pull Request, und automatisierte Checks schlagen fehl. ❌
$ git push origin feature/road-profile-viewer
Running automated checks...
❌ Ruff check: 14 errors found
❌ Format check: 8 files need formatting
❌ Type check: 6 type errors detected
Pull request blocked - fix issues before merging
Was ist passiert? Ihr Code funktioniert, aber er erfüllt nicht die professionellen Qualitätsstandards. Das ist die Lücke zwischen Hobby-Code und produktionsreifer Software.
Diese Vorlesung handelt davon, diese Lücke zu verstehen und zu schließen—nicht mit mühsamen manuellen Reviews, sondern mit automatisierten Tools, die Qualitätskontrolle mühelos und konsistent machen.
2. Lernziele
Am Ende dieser Vorlesung werden Sie:
- Den Unterschied verstehen zwischen Code, der funktioniert, und Code, der professionellen Standards entspricht
- Häufige Code-Qualitätsprobleme erkennen anhand realer Beispiele aus dem Road Profile Viewer Projekt
- Sich überschneidende Qualitätskonzepte unterscheiden: Style Guides, Linting, Formatting, Type Hints und Type Checking—verstehen, was jedes davon tut und wie sie sich ergänzen
- Über Pythons Style Guide (PEP 8) lernen und warum er für professionelle Entwicklung wichtig ist
- Moderne Qualitäts-Tools beherrschen:
- Ruff: Der All-in-One-Linter und Formatter, der PEP 8 durchsetzt und Bugs findet
- Pyright: Der Type Checker, der Type Annotations validiert und typbezogene Fehler verhindert
- Verstehen, warum wir sowohl Ruff ALS AUCH Pyright brauchen: Sie arbeiten auf verschiedenen Ebenen (Style/Bugs vs. Type Safety)
- Automatisierte Checks anwenden, um Probleme vor menschlicher Review zu finden
- Qualität von Anfang an in Ihren Workflow einbauen, nicht als nachträglichen Gedanken
- Den Business Case für Code-Qualität schätzen: reduzierte Kosten, schnelleres Debugging und bessere Team-Zusammenarbeit
3. Teil 1: Die Realitätsprüfung - Unser Code unter Beobachtung
Schauen wir uns echten Code aus dem Road Profile Viewer Projekt an und sehen, was automatisierte Tools finden.
3.1 Der Code, den wir geschrieben haben
Hier ist ein Ausschnitt aus main.py:
"""
Road Profile Viewer - Interactive 2D Visualization
"""
import numpy as np
from dash import Dash, html, dcc, Input, Output
import plotly.graph_objects as go
import sys,os # Multiple imports on one line
def generate_road_profile(num_points=100,x_max=80):
"""Generate a road profile using a clothoid-like approximation."""
x = np.linspace(0, x_max, num_points)
x_norm = x / x_max
# Clothoid approximation
y=0.015 * x_norm**3 * x_max + 0.3 * np.sin(2 * np.pi * x_norm)
y = y - y[0]
return x,y
def HelperFunction(val):
"""Unused helper function that violates naming convention"""
result=val*2
return result
# Later in the code...
camera_x,camera_y = 0,2.0
marker=dict(size=12,color='red',symbol='circle')
# Add camera ray - This is a very long comment that exceeds the recommended 79 character line length limit specified in PEP8 style guide
Erster Eindruck? Sieht vernünftig aus. Es funktioniert. Aber schauen wir, was die Tools sagen…
3.2 Ausführen automatisierter Checks
$ uv run ruff check .
src/road_profile_viewer/main.py:16:1: E401 Multiple imports on one line
src/road_profile_viewer/main.py:16:8: F401 `sys` imported but unused
src/road_profile_viewer/main.py:16:12: F401 `os` imported but unused
src/road_profile_viewer/main.py:24:5: E701 Multiple statements on one line (colon)
src/road_profile_viewer/main.py:29:5: E225 Missing whitespace around operator
src/road_profile_viewer/main.py:32:12: E231 Missing whitespace after ','
src/road_profile_viewer/main.py:36:1: N802 Function name should be lowercase
src/road_profile_viewer/main.py:36:1: F841 Local variable `HelperFunction` is assigned but never used
src/road_profile_viewer/main.py:38:11: E225 Missing whitespace around operator
src/road_profile_viewer/main.py:43:14: E231 Missing whitespace after ','
src/road_profile_viewer/main.py:43:24: E231 Missing whitespace after ','
src/road_profile_viewer/main.py:45:8: E225 Missing whitespace around operator
src/road_profile_viewer/main.py:45:13: E231 Missing whitespace after ','
src/road_profile_viewer/main.py:47:1: E501 Line too long (149 > 88 characters)
Found 14 errors.
14 Fehler in Code, der perfekt funktioniert! Das ist der Unterschied zwischen “läuft auf meiner Maschine” und “erfüllt professionelle Standards.”
Diese automatisierten Tools prüfen gegen Pythons etablierte Style-Richtlinien und Best Practices. Wir werden die Grundlage dieser Standards—Pythons offiziellen Style Guide—später in dieser Vorlesung erkunden. Für jetzt, lassen Sie uns verstehen, was jedes Problem bedeutet und warum es wichtig ist.
Lassen Sie uns jedes Problem aufschlüsseln und verstehen warum es wichtig ist.
4. Teil 2: Code-Qualitätsprobleme verstehen
4.1 Problem-Kategorie 1: Import-Verstöße
4.1.1 Das Problem
import sys,os # SCHLECHT: Mehrere Imports in einer Zeile
Was ist falsch?
- Mehrere Imports in einer Zeile (sollten getrennt sein)
- Sowohl
sysals auchoswerden importiert, aber nie verwendet
Ruff meldet:
E401: Mehrere Imports in einer ZeileF401: ‘sys’ importiert, aber nicht verwendetF401: ‘os’ importiert, aber nicht verwendet
4.1.2 Warum das wichtig ist
Für Computer: Das Importieren ungenutzter Module verschwendet Speicher und Startzeit. In diesem kleinen Beispiel ist es vernachlässigbar, aber in großen Anwendungen mit Dutzenden ungenutzter Imports sammelt es sich an.
Für Menschen:
Wenn Sie import sys sehen, erwarten Sie, dass der Code sys irgendwo verwendet. Ungenutzte Imports erzeugen Verwirrung:
- “Warum brauchen wir hier
sys?” - “Übersehe ich etwas?”
- “Kann ich das sicher entfernen?”
Für Wartbarkeit: Ungenutzte Imports sammeln sich über Zeit an. Jemand fügt einen Import für einen schnellen Test hinzu, vergisst ihn zu entfernen, und er bleibt für immer. Nach ein paar Jahren hat Ihre Datei 20 Imports, aber verwendet nur 10. Viel Glück dabei herauszufinden, welche sicher entfernt werden können!
4.1.3 Die Lösung
# GUT: Getrennte Imports, nur importieren, was Sie verwenden
import numpy as np
from dash import Dash, html, dcc, Input, Output
import plotly.graph_objects as go
Python Best Practice: Imports sollten normalerweise in separaten Zeilen stehen für bessere Lesbarkeit und Wartbarkeit.
# Gut
import os
import sys
# Schlecht
import sys, os
4.2 Problem-Kategorie 2: Fehlende Leerzeichen
4.2.1 Das Problem
# SCHLECHT: Fehlende Leerzeichen überall
def generate_road_profile(num_points=100,x_max=80):
y=0.015 * x_norm**3 * x_max
return x,y
camera_x,camera_y = 0,2.0
result=val*2
marker=dict(size=12,color='red',symbol='circle')
Ruff meldet:
E231: Fehlendes Leerzeichen nach ‘,’E225: Fehlendes Leerzeichen um Operator
4.2.2 Warum das wichtig ist
Lesbarkeit ist König
Vergleichen Sie diese beiden Versionen:
# Schwer zu lesen - alles läuft zusammen
marker=dict(size=12,color='red',symbol='circle')
# Leicht zu lesen - klare Trennung
marker = dict(size=12, color='red', symbol='circle')
Welche können Sie schneller erfassen? Die zweite, offensichtlich.
Die Wissenschaft dahinter
Forschung in kognitiver Psychologie zeigt, dass Menschen visuelle Information in “Chunks” verarbeiten. Leerzeichen schaffen natürliche Grenzen zwischen Chunks, wodurch Code leichter zu scannen und zu verstehen ist.
Ihr Gehirn verarbeitet die zweite Version ~30% schneller, weil es nicht so hart arbeiten muss, um die Information zu segmentieren.
Reale Auswirkung
- Code-Review-Zeit: Entwickler verbringen 60-80% ihrer Zeit mit dem Lesen von Code, nicht mit dem Schreiben
- Bug-Erkennung: Dichter, zusammengedrängter Code versteckt Bugs effektiver als gut formatierter Code
- Onboarding: Neue Teammitglieder verstehen gut formatierten Code 30-40% schneller
Versionskontroll-Vorteile
Konsistente Leerzeichen-Platzierung hilft, unerwünschte Diffs in zukünftigen Commits zu vermeiden. Betrachten Sie dieses Szenario:
# Inkonsistente Abstände - Änderungen erzeugen verrauschte Diffs
marker=dict(size=12,color='red') # Erster Commit
marker = dict(size=12, color='red', symbol='circle') # Später: Parameter hinzugefügt
Der Diff zeigt, dass sich die gesamte Zeile geändert hat, wodurch es schwer zu erkennen ist, dass nur symbol='circle' hinzugefügt wurde. Vergleichen Sie:
# Konsistente Abstände von Anfang an - saubere Diffs
marker = dict(size=12, color='red') # Erster Commit
marker = dict(size=12, color='red', symbol='circle') # Später: nur neuer Parameter sichtbar
Grundprinzip: Wenn alle im Team dieselben Leerzeichen-Regeln befolgen, zeigen Git-Diffs tatsächliche Logikänderungen anstelle von Stiländerungen. Dies macht Code-Reviews schneller und effektiver.
4.2.3 Die Lösung
# GUT: Richtige Abstände
def generate_road_profile(num_points=100, x_max=80):
y = 0.015 * x_norm**3 * x_max
return x, y
camera_x, camera_y = 0, 2.0
result = val * 2
marker = dict(size=12, color='red', symbol='circle')
Professioneller Python-Style:
- Umgeben Sie diese binären Operatoren immer mit einem einzigen Leerzeichen auf beiden Seiten: Zuweisung (
=), erweiterte Zuweisung (+=,-=, etc.), Vergleiche (==,<,>,!=,<=,>=,in,not in,is,is not), Booleans (and,or,not) - Verwenden Sie Leerzeichen nach Kommas in Argumentlisten, Funktionsaufrufen und Datenstrukturen
4.3 Problem-Kategorie 3: Namenskonventionen
4.3.1 Das Problem
def HelperFunction(val): # SCHLECHT: PascalCase für Funktion
"""Unused helper function"""
result = val * 2
return result
Ruff meldet:
N802: Funktionsname sollte Kleinbuchstaben seinF841: Lokale VariableHelperFunctionwird zugewiesen, aber nie verwendet
4.3.2 Warum das wichtig ist
Namenskonventionen sind eine gemeinsame Sprache
In Python gibt es etablierte Namensmuster, die verschiedene Arten von Code-Elementen signalisieren:
PascalCasebedeutet “das ist eine Klasse” (z.B.RoadProfile,CameraRay)snake_casebedeutet “das ist eine Funktion oder Variable” (z.B.calculate_total,camera_x)UPPER_CASEbedeutet “das ist eine Konstante” (z.B.MAX_SPEED,PI)
Diese Konventionen sind in Pythons offiziellem Style Guide formalisiert, den wir später in dieser Vorlesung im Detail erkunden werden.
Wenn Sie HelperFunction() sehen, denkt Ihr Gehirn “Klasse.” Wenn Sie versuchen, es zu verwenden und entdecken, dass es eine Funktion ist, erleben Sie kognitive Dissonanz. Dieser winzige Moment der Verwirrung passiert Hunderte Male beim Lesen von Code.
Das Prinzip: Geringste Überraschung
Code sollte sich so verhalten, wie Leser es erwarten. Konventionen zu brechen erzeugt Überraschung (und Frustration).
Echtes Beispiel aus der Produktion
# Jemand hat dies in einer echten Codebasis geschrieben
DatabaseConnection = connect_to_db() # Sieht aus wie eine Klasse!
# Später versuchte ein anderer Entwickler:
conn = DatabaseConnection() # TypeError: 'Connection' object is not callable
Das kostete 2 Stunden Debugging, weil die Benennung Erwartungen verletzte.
4.3.3 Die Lösung
# GUT: Klare Namenskonvention
def helper_function(val):
"""Calculate double of input value."""
result = val * 2
return result
Aber warten Sie! Diese Funktion wird auch nie verwendet…
4.4 Problem-Kategorie 4: Toter Code
4.4.1 Das Problem
def HelperFunction(val):
"""Unused helper function"""
result = val * 2
return result
# Diese Funktion wird nirgendwo im Code aufgerufen
Ruff meldet:
F841: Lokale VariableHelperFunctionwird zugewiesen, aber nie verwendet
4.4.2 Warum das wichtig ist
Toter Code ist technische Schuld
Jede Zeile Code hat Kosten:
1. Wartungskosten Jemand muss ihn warten, auch wenn er nicht verwendet wird:
- Updates für API-Änderungen
- Sicherheits-Patches
- Python-Versionskompatibilität
2. Kognitive Kosten Zukünftige Entwickler müssen ihn lesen und verstehen:
- “Ist diese Funktion wichtig?”
- “Warum wurde sie geschrieben, wenn sie nicht verwendet wird?”
- “Kann ich sie sicher löschen?”
3. Test-Kosten Toter Code wird oft trotzdem getestet:
- Verschwendete Test-Abdeckung
- Falsches Sicherheitsgefühl
Reales Szenario
# Sie müssen ändern, wie Koordinaten funktionieren
# Sie aktualisieren alle Koordinatenfunktionen...
def calculate_position(x, y, z): # ✅ Aktualisiert!
return Vector3D(x, y, z)
def transform_point(point): # ✅ Aktualisiert!
return point.to_3d()
def HelperFunction(val): # ❌ Vergessen, dies zu aktualisieren!
# Verwendet immer noch alte 2D-Logik
return val * 2
Der tote Code bricht nichts (er wird nicht aufgerufen), aber er sitzt da wie eine tickende Zeitbombe. Wenn jemand ihn später entdeckt und versucht zu verwenden, wird er veraltete Logik verwenden.
4.4.3 Die Lösung
# GUT: Toten Code löschen
# Wenn Sie ihn später brauchen, dafür gibt es Versionskontrolle (Git)!
Schlüsselprinzip: Wenn Code nicht verwendet wird, entfernen Sie ihn. Git erinnert sich an alles.
4.5 Problem-Kategorie 5: Zeilenlänge
4.5.1 Das Problem
# Add camera ray - This is a very long comment that exceeds the recommended 79 character line length limit specified in PEP8 style guide
Ruff meldet:
E501: Zeile zu lang (149 > 88 Zeichen)
4.5.2 Warum das wichtig ist
Bildschirmplatz ist begrenzt
Betrachten Sie diese Szenarien:
Szenario 1: Side-by-side Code Review
[Ihre Code-Datei ] | [Kommentare des Reviewers]
[ ] | [ ]
Mit 150-Zeichen-Zeilen muss der Reviewer ständig horizontal scrollen. Das ist anstrengend und fehleranfällig.
Szenario 2: Split-Screen-Entwicklung
[Implementierungsdatei] | [Testdatei ]
[Alte Code-Version ] | [Neue Code-Version ]
Lange Zeilen zwingen Sie zum Vollbild-Arbeiten, wodurch Sie Produktivitätsvorteile geteilter Ansichten verlieren.
Szenario 3: Code-Diffs
- marker=dict(size=12,color='red',symbol='circle',shape='diamond',opacity=0.8,line=dict(width=2,color='black'))
+ marker=dict(size=12,color='blue',symbol='circle',shape='diamond',opacity=0.8,line=dict(width=2,color='black'))
Können Sie die Änderung erkennen? Es ist color='red' → color='blue', aber es ist in einer 120-Zeichen-Zeile vergraben.
Vergleichen Sie mit:
marker = dict(
size=12,
- color='red',
+ color='blue',
symbol='circle',
shape='diamond',
)
Die Änderung ist sofort offensichtlich.
Die Forschung
Studien zeigen, dass das Verständnis signifikant abnimmt, wenn Zeilen länger als 60-80 Zeichen gelesen werden. Ihre Augen müssen längere Sakkaden (Sprünge) machen, und Sie verlieren leichter Ihre Position.
4.5.3 Die Lösung
# GUT: Lange Zeilen logisch umbrechen
marker = dict(
size=12,
color='red',
symbol='circle'
)
# GUT: Lange Kommentare umbrechen
# Add camera ray - Dieser Kommentar ist in mehrere Zeilen aufgeteilt,
# um empfohlene Zeilenlängenbeschränkungen für bessere Lesbarkeit zu respektieren
Professionelle Style-Richtlinie:
- Begrenzen Sie alle Zeilen auf maximal 79 Zeichen
- Für Docstrings oder Kommentare auf 72 Zeichen begrenzen
- Moderne Interpretation: 88-100 Zeichen ist akzeptabel (Black/Ruff Standard)
5. Teil 3: Das große Bild - Warum Code-Qualität wichtig ist
Jetzt, da wir spezifische Probleme gesehen haben, lassen Sie uns herauszoomen und die Prinzipien verstehen.
5.1 Prinzip 1: Code wird mehr gelesen als geschrieben
Die 10:1-Regel
Für jede Stunde, die mit dem Schreiben von Code verbracht wird, werden ungefähr 10 Stunden mit dem Lesen verbracht.
Denken Sie an Ihren Entwicklungsprozess:
- Sie schreiben ein Feature (1 Stunde)
- Sie debuggen es (lesen Ihren Code) (30 Min.)
- Ihr Kollege reviewt es (liest Ihren Code) (20 Min.)
- Zukünftiges Ich fügt ein Feature hinzu (liest alten Code) (1 Stunde)
- Neues Teammitglied lernt die Codebasis (liest Ihren Code) (2 Stunden)
- Jemand behebt einen Bug (liest Ihren Code) (1 Stunde)
Total: 5,5 Stunden Lesen, 1 Stunde Schreiben.
Code-Qualität optimiert für Lesen, nicht Schreiben.
5.2 Prinzip 2: Konsistenz reduziert kognitive Last
Ihr Gehirn ist eine Mustererkennungsmaschine. Wenn Code konsistent ist:
- Erkennen Sie Muster sofort
- Erkennen Sie Anomalien schnell
- Verstehen Sie Absichten schneller
Beispiel:
# Inkonsistente Abstände - Ihr Gehirn muss jede Zeile einzeln parsen
x_road,y_road = generate_road_profile(num_points=100, x_max=80)
camera_x, camera_y = 0, 2.0
result= calculate_value(a,b)
# Konsistente Abstände - Ihr Gehirn erkennt das Muster
x_road, y_road = generate_road_profile(num_points=100, x_max=80)
camera_x, camera_y = 0, 2.0
result = calculate_value(a, b)
Die zweite Version fühlt sich “glatter” an, weil Ihr Gehirn nicht für jede Zeile den Kontext wechseln muss.
5.3 Prinzip 3: Früherkennung verhindert teure Bugs
Die Kosten von Bugs wachsen exponentiell
| Wann gefunden | Relative Kosten | Beispiel |
|---|---|---|
| Beim Schreiben | 1x | "Hoppla, Tippfehler!" (5 Sekunden zu beheben) |
| Während Code Review | 10x | "Lass mich einen Fix pushen..." (5 Minuten) |
| Während QA-Tests | 100x | "Muss debuggen, fixen, retesten" (1 Stunde) |
| In Produktion | 1000x+ | "Notfall-Hotfix, Kundenentschädigung, Reputationsschaden" (Tage/Wochen) |
Echtes Beispiel aus unserem Code
def find_intersection(x_road, y_road, angle_degrees, camera_x=0, camera_y=1.5):
# ... code ...
return x_intersect, y_intersect, distance
# Später:
x_intersect, y_intersect, distance = find_intersection(...)
Das funktioniert gut. Aber stellen Sie sich vor, jemand ändert es ohne Type Hints:
def find_intersection(x_road, y_road, angle_degrees, camera_x=0, camera_y=1.5):
# ... code ...
return distance # Hoppla! Vergessen, x und y zurückzugeben
# Später:
x_intersect, y_intersect, distance = find_intersection(...) # BOOM! Runtime-Fehler
Ohne Type Checking: Dieser Bug erreicht die Produktion, stürzt ab, wenn ein Benutzer den Winkel anpasst.
Mit Type Checking:
def find_intersection(
x_road: np.NDArray,
y_road: np.NDArray,
angle_degrees: float,
camera_x: float = 0,
camera_y: float = 1.5
) -> tuple[float, float, float] | tuple[None, None, None]:
# ... code ...
return distance # Type Checker: Fehler! Erwartete tuple[float, float, float]
Gefangen in 2 Sekunden, nicht 2 Wochen.
5.4 Prinzip 4: Automatisierung skaliert, Menschen nicht
Die Mathematik
Stellen Sie sich vor, Sie sind Teamleiter mit 10 Entwicklern. Ohne Automatisierung:
Manuelle Code-Review pro Pull Request: 30 Minuten
Pull Requests pro Woche: 50
Gesamte Review-Zeit: 25 Stunden/Woche
Sie müssen jemanden nur für Code-Reviews einstellen!
Mit Automatisierung:
Automatisierte Checks pro Pull Request: 2 Minuten
Pull Requests pro Woche: 50
Gesamte automatisierte Zeit: 100 Minuten/Woche
Menschliche Review-Zeit pro PR: 10 Minuten (Fokus auf Logik, nicht Style)
Gesamte menschliche Zeit: 8,3 Stunden/Woche
Gesparte Zeit: 16,7 Stunden/Woche = 867 Stunden/Jahr pro Team
Bei $100/Stunde (typische Entwicklerkosten) sind das $86.700 gespart pro Jahr.
6. Teil 4: PEP 8 - Die Grundlage der Python-Code-Qualität
In dieser Vorlesung haben wir gesehen, wie automatisierte Tools Probleme wie Import-Formatierung, Abstände, Namenskonventionen und Zeilenlänge finden. Sie fragen sich vielleicht: Woher kommen diese Regeln? Wer entscheidet, was “korrekt” ist?
Die Antwort ist PEP 8—Pythons offizieller Style Guide, der die Grundlage all dieser Qualitätsstandards bildet.
6.1 Was ist PEP 8?
PEP 8 ist Pythons offizieller Style Guide. PEP steht für “Python Enhancement Proposal”—so entwickelt sich Python als Sprache weiter.
- Geschrieben von: Guido van Rossum (Pythons Schöpfer), Barry Warsaw und Nick Coghlan
- Erstmals veröffentlicht: 2001
- Status: Aktiv (regelmäßig aktualisiert)
- Offizielles Dokument: python.org/dev/peps/pep-0008
PEP 8 sind keine Vorschläge—es ist der von der Community vereinbarte Standard.
6.2 Warum PEP 8 befolgen?
6.2.1 Grund 1: Es ist eine gemeinsame Sprache
Wenn Sie PEP 8 befolgen:
- Sieht Ihr Code wie Python-Code aus
- Andere Python-Entwickler verstehen Ihren Style sofort
- Sie können jeden PEP 8-konformen Code leicht lesen
Es ist wie die Verwendung standardisierter deutscher Rechtschreibung. Sie könnten “Farbe” als “Varbe” schreiben, aber niemand würde Sie verstehen.
6.2.2 Grund 2: Tooling erwartet es
Alle wichtigen Python-Tools gehen von PEP 8 aus:
- IDEs bieten Auto-Complete basierend auf PEP 8-Benennung
- Linters prüfen gegen PEP 8-Regeln
- Formatter erzwingen PEP 8-Style
- Dokumentationsgeneratoren erwarten PEP 8-Konventionen
Gegen PEP 8 zu kämpfen bedeutet, gegen das gesamte Ökosystem zu kämpfen.
6.2.3 Grund 3: Einstellung und Karriere
Wenn Unternehmen Python-Entwickler einstellen, erwarten sie PEP 8-Kenntnisse. Code, der PEP 8 nicht befolgt, ist ein rotes Fähnchen bei:
- Technischen Interviews
- GitHub-Portfolios
- Open-Source-Beiträgen
- Code-Beispielen für Bewerbungen
6.3 Wichtige PEP 8-Regeln (Kurzreferenz)
Einrückung
# Verwenden Sie 4 Leerzeichen pro Einrückungsebene (keine Tabs)
def example_function():
if True:
print("Vier Leerzeichen")
Zeilenlänge
# Begrenzen Sie Zeilen auf 79 Zeichen (oder 88 mit modernen Tools)
# Brechen Sie lange Zeilen an logischen Punkten um
result = some_function(
argument1,
argument2,
argument3
)
Imports
# Imports am Anfang der Datei, gruppiert in Reihenfolge:
# 1. Standardbibliothek
# 2. Drittanbieter
# 3. Lokale Anwendung
import os
import sys
import numpy as np
from dash import Dash
from myapp import utils
Namenskonventionen
# Funktionen und Variablen: snake_case
def calculate_average(numbers):
total_sum = sum(numbers)
return total_sum / len(numbers)
# Klassen: PascalCase
class RoadProfile:
pass
# Konstanten: UPPER_CASE
MAX_SPEED = 100
PI = 3.14159
Leerzeichen
# Ja: Leerzeichen um Operatoren und nach Kommas
result = x + y
my_list = [1, 2, 3]
func(a, b, c)
# Nein: Fehlende Leerzeichen
result=x+y
my_list=[1,2,3]
func(a,b,c)
Kommentare
# Verwenden Sie Inline-Kommentare sparsam
x = x + 1 # Kompensiere für Rand
# Verwenden Sie Docstrings für Funktionen
def calculate_average(numbers):
"""
Berechnet das arithmetische Mittel einer Liste von Zahlen.
Args:
numbers: Liste numerischer Werte
Returns:
float: Der Durchschnittswert
"""
return sum(numbers) / len(numbers)
7. Teil 5: Moderne Tools - Die Ruff-Revolution
7.1 Die Evolution der Python-Code-Qualitäts-Tools
Traditioneller Ansatz (Vor 2023):
- Flake8 für Linting
- Black für Formatierung
- isort für Import-Sortierung
- mypy für Type Checking
- pylint für zusätzliche Checks
Jedes Tool hatte seine eigene Konfiguration, lief separat und brauchte erhebliche Zeit.
Moderner Ansatz (2024+):
- Ruff für Linting, Formatierung und Import-Sortierung
- Pyright für Type Checking
Zwei Tools. Blitzschnell. Eine Konfigurationsdatei.
7.2 Was ist Ruff?
Ruff ist ein moderner Python-Linter und -Formatter, geschrieben in Rust. Er wird von Astral entwickelt, derselben Firma hinter uv.
Hauptmerkmale:
- 10-100x schneller als traditionelle Python-Tools
- Ersetzt Flake8, Black, isort und viele Flake8-Plugins
- 800+ Regeln aus mehreren Quellen
- Auto-Fix für viele Probleme
- Null Konfiguration für den Start
- Kompatibel mit bestehenden Black/Flake8-Konfigurationen
7.3 Ruff installieren - Dependency Management verstehen
Bevor wir Ruff verwenden können, müssen wir verstehen, wo und wie man es installiert. Das ist entscheidend, damit unsere Befehle funktionieren!
7.3.1 Das Problem: uv run ruff funktioniert (noch) nicht
Wenn Sie jetzt versuchen, Ruff auszuführen:
$ uv run ruff check .
error: program not found: ruff
Warum? Weil uv run nach ruff im .venv-Verzeichnis Ihres Projekts sucht, und wir es dort noch nicht installiert haben!
Das führt zu einer wichtigen Frage: Wo sollten wir Ruff installieren?
7.3.2 Drei Arten, Python-Pakete zu verwenden
Das Verständnis, wie man Abhängigkeiten richtig verwaltet, ist entscheidend für:
- Reproduzierbarkeit: Sicherstellen, dass Ihr Projekt auf verschiedenen Maschinen gleich funktioniert
- Zusammenarbeit: Teammitglieder können sofort die exakt gleiche Entwicklungsumgebung erhalten
- Wartung: Klare Trennung zwischen Produktionscode und Entwicklungstools
- Effizienz: Verwirrung vermeiden, wo Pakete installiert sind und wie man sie ausführt
Lassen Sie uns die drei Kontexte erkunden, in denen Python-Pakete installiert werden können:
1. Projekt-Abhängigkeiten ([project.dependencies])
Was: Pakete, die Ihre Anwendung zum Laufen in der Produktion BRAUCHT.
Für unseren Road Profile Viewer sind das die Pakete, die installiert sein müssen, damit die Anwendung funktioniert:
[project]
dependencies = [
"dash>=2.14.0",
"plotly>=5.18.0",
"numpy>=1.26.0",
]
Hinzufügen mit:
uv add dash plotly numpy
Wann verwenden: Wenn das Paket zum Ausführen der Anwendung erforderlich ist.
2. Entwicklungs-Abhängigkeiten ([dependency-groups.dev])
Was: Tools, die Sie für die ENTWICKLUNG benötigen, aber nicht zum Ausführen der App (Linter, Formatter, Test-Frameworks).
Hier gehört Ruff hin! Ruff ist ein Entwicklungstool – wir verwenden es, um unseren Code zu prüfen und zu formatieren, aber der Road Profile Viewer braucht Ruff nicht zum Laufen.
[dependency-groups]
dev = [
"ruff>=0.8.0",
"pytest>=7.0.0",
]
Hinzufügen mit:
uv add --dev ruff pytest
Wann verwenden: Wenn Sie das Tool für Entwicklung, Testing oder Code-Qualität benötigen, aber nicht zum Ausführen der Anwendung.
3. Globale Tools (uv tool install)
Was: CLI-Tools, die Sie systemweit in ALLEN Projekten verfügbar haben möchten.
uv tool install ruff
Wann verwenden: Wenn Sie ein Tool überall verfügbar haben möchten, ohne es zu den Abhängigkeiten jedes Projekts hinzuzufügen.
Abwägung:
- ✅ In allen Projekten sofort verfügbar
- ❌ Nicht in
pyproject.tomldokumentiert (Teammitglieder wissen nicht, dass sie es installieren sollen) - ❌ Version kann zwischen Teammitgliedern unterschiedlich sein
7.3.3 Entscheidungsbaum: Wo sollte Ruff hin?
Wird Ruff benötigt, um die Road Profile Viewer Anwendung AUSZUFÜHREN?
└─ NEIN → Es ist ein Entwicklungstool
Ist Ruff spezifisch für DIESES Projekt?
└─ JA → Wir wollen konsistente Versionen im Team
Wollen wir es in der Versionskontrolle dokumentieren?
└─ JA → Teammitglieder sollten es in pyproject.toml sehen
✅ Entscheidung: Als Entwicklungs-Abhängigkeit installieren
7.3.4 Ruff für unser Projekt installieren
Schritt 1: Ruff als Entwicklungs-Abhängigkeit hinzufügen
uv add --dev ruff
Dies ändert Ihre pyproject.toml:
[project]
name = "road-profile-viewer"
version = "0.1.0"
dependencies = [
"dash>=2.14.0",
"plotly>=5.18.0",
"numpy>=1.26.0",
]
[dependency-groups]
dev = [
"ruff>=0.8.0", # ← Hier hinzugefügt!
]
Schritt 2: Alle Abhängigkeiten installieren (inklusive dev)
uv sync --group dev
Dies installiert:
- Alle Produktions-Abhängigkeiten (dash, plotly, numpy)
- Alle Entwicklungs-Abhängigkeiten (ruff)
Schritt 3: Verifizieren, dass Ruff installiert ist
uv run ruff --version
# Ausgabe: ruff 0.8.0
Jetzt funktioniert uv run ruff! 🎉
7.3.5 uv run Verhalten verstehen
Wenn Sie uv run <command> ausführen, passiert Folgendes:
1. uv sucht nach pyproject.toml (durchsucht Verzeichnisbaum nach oben)
2. uv prüft, ob <command> im .venv des Projekts existiert
3. Wenn gefunden: führt es mit der Python-Umgebung des Projekts aus
4. Wenn nicht gefunden: Fehler "program not found"
Häufige Verwirrung:
❌ Das funktioniert NICHT (Ruff noch nicht im .venv):
uv run ruff check .
# Fehler: program not found
✅ Das FUNKTIONIERT (nach uv add --dev ruff):
uv run ruff check .
# Läuft erfolgreich!
✅ Das FUNKTIONIERT (temporäre Installation, ändert Projekt nicht):
uv run --with ruff ruff check .
# Erstellt temporäre Umgebung mit ruff und führt es aus
✅ Das FUNKTIONIERT (wenn global installiert):
uv tool install ruff
ruff check . # Direkt ausführen, kein uv run nötig
7.3.6 Best Practice: Entwicklungs-Setup dokumentieren
Fügen Sie einen Abschnitt zu Ihrer README.md hinzu:
## 8. Entwicklungs-Setup {#entwicklungs-setup}
### 8.1 Abhängigkeiten installieren {#abhängigkeiten-installieren}
```bash
# Alle Abhängigkeiten installieren (inklusive Entwicklungstools)
uv sync --group dev
8.2 Verfügbare Entwicklungs-Befehle
# Linter ausführen
uv run ruff check .
# Linting-Probleme automatisch beheben
uv run ruff check --fix .
# Code formatieren
uv run ruff format .
# Anwendung ausführen
uv run road-profile-viewer
Dies stellt sicher, dass neue Teammitglieder genau wissen, wie sie ihre Umgebung einrichten!
8.2.1 Zusammenfassung: Dependency Management mit uv
| Befehl | Zweck | Ändert pyproject.toml? |
|---|---|---|
uv add <paket> |
Produktions-Abhängigkeit hinzufügen | ✅ Ja → [project.dependencies] |
uv add --dev <paket> |
Entwicklungs-Abhängigkeit hinzufügen | ✅ Ja → [dependency-groups.dev] |
uv sync |
Nur Produktions-Abhängigkeiten installieren | ❌ Nein |
uv sync --group dev |
Alle Abhängigkeiten installieren (Prod + Dev) | ❌ Nein |
uv run <befehl> |
Befehl in Projekt-Umgebung ausführen | ❌ Nein |
uv run --with <pkg> <cmd> |
Temporäre Paketverwendung | ❌ Nein |
uv tool install <paket> |
Globales CLI-Tool installieren | ❌ Nein |
Kernaussage: Entwicklungstools wie Ruff sollten mit uv add --dev installiert werden, um:
- ✅ Sie in
pyproject.tomlzu dokumentieren - ✅ Konsistente Versionen im Team sicherzustellen
- ✅ Setup reproduzierbar zu machen
- ✅
uv runzu ermöglichen, sie zu finden
8.3 Ruff Check - Der Linter
Jetzt, da Ruff ordnungsgemäß als Entwicklungs-Abhängigkeit installiert ist, lassen Sie uns erkunden, was es kann!
Was es tut: Analysiert Code auf Fehler, Bugs, Style-Verstöße und Code-Smells.
Ruff Check ausführen:
# Alle Dateien im aktuellen Verzeichnis prüfen
uv run ruff check .
# Spezifische Datei prüfen
uv run ruff check src/main.py
# Probleme automatisch beheben, wo möglich
uv run ruff check --fix .
# Zeigen, was behoben würde, ohne Dateien zu ändern
uv run ruff check --fix --diff .
Beispiel-Ausgabe:
$ uv run ruff check .
src/main.py:16:1: E401 [*] Multiple imports on one line
src/main.py:16:8: F401 [*] `sys` imported but unused
src/main.py:29:5: E225 [*] Missing whitespace around operator
src/main.py:36:1: N802 Function name `HelperFunction` should be lowercase
src/main.py:47:1: E501 Line too long (149 > 88 characters)
Found 5 errors.
[*] 3 fixable with the `--fix` option.
Das [*] zeigt automatisch behebbare Probleme an.
8.4 Ruff Format - Der Code-Formatter
Was es tut: Formatiert Code automatisch, um konsistenten Style-Regeln zu folgen (kompatibel mit Black).
Ruff Format ausführen:
# Alle Dateien formatieren
uv run ruff format .
# Prüfen, ob Formatierung benötigt wird (ändert keine Dateien)
uv run ruff format --check .
# Zeigen, was sich ändern würde (Diff-Modus)
uv run ruff format --diff .
Vorher:
def generate_road_profile(num_points=100,x_max=80):
y=0.015 * x_norm**3 * x_max
return x,y
Nachher:
def generate_road_profile(num_points=100, x_max=80):
y = 0.015 * x_norm**3 * x_max
return x, y
8.5 Ruff konfigurieren
8.5.1 pyproject.toml Sections verstehen
Erinnern Sie sich, dass pyproject.toml zwei Hauptarten von Sektionen hat:
- Standardisierte Sektionen (definiert durch Python PEPs):
[project]- Projekt-Metadaten und Abhängigkeiten[dependency-groups]- Optionale Abhängigkeitsgruppen wiedev
- Tool-spezifische Sektionen mit
[tool.*]Namespace:[tool.ruff]- Ruff-Konfiguration[tool.pytest]- pytest-Konfiguration[tool.mypy]- mypy-Konfiguration
Dies hält alle Tool-Konfigurationen in einer Datei, statt über .ruff.toml, .pytest.ini usw. verstreut zu sein.
8.5.2 Warum Ruff anpassen?
Ruff funktioniert mit seinen Standardwerten großartig, aber Sie möchten es anpassen, weil:
1. Projekt-spezifische Anforderungen
- Ihr Team verwendet möglicherweise 100-Zeichen-Zeilen statt Ruffs Standard von 88
- Sie benötigen möglicherweise spezifische Python-Versions-Kompatibilität (z.B.
py312vspy310) - Legacy-Code benötigt möglicherweise bestimmte Regeln vorübergehend ignoriert
2. Mehr Regeln aktivieren
- Standardmäßig aktiviert Ruff nur grundlegende Prüfungen (ähnlich wie Flake8)
- Sie können Hunderte zusätzlicher Regeln aktivieren:
I- Import-Sortierung (wie isort)N- Namenskonventionen (PEP 8)B- Fehlererkennung (wie flake8-bugbear)UP- Moderne Python-Syntax-Upgrades
3. Team-Konsistenz
- Konfiguration in
pyproject.tomlstellt sicher, dass alle dieselben Regeln verwenden - Vermeiden Sie Diskussionen: “Es funktioniert auf meinem Rechner!” → “Schau in die pyproject.toml!”
4. CI/CD-Integration
- Dieselbe Konfiguration läuft lokal und in automatisierten Pipelines
- Keine Überraschungen, wenn Code lokal funktioniert, aber im CI fehlschlägt
8.5.3 Ihre Ruff-Konfiguration
KI nutzen: Fokus auf Anforderungen, nicht auf Syntax
Anstatt TOML-Syntax und Ruff-Konfigurationsoptionen auswendig zu lernen, nutzen wir KI, um unsere Anforderungen in Konfiguration zu übersetzen. Das ist moderne Entwicklung: Fokus auf das, was Sie brauchen, KI übernimmt die Syntax-Details.
Schritt 1: Definieren Sie Ihre Anforderungen
Überlegen Sie, was Ihr Projekt braucht:
- Maximale Zeilenlänge: 88 Zeichen (Black/Ruff-Standard)
- Python-Version: 3.12
- Zusätzliche Prüfungen über Basics hinaus: Import-Sortierung, Namenskonventionen, Fehlererkennung, moderne Syntax
- Code-Formatierung: Doppelte Anführungszeichen, Unix-Zeilenenden
Schritt 2: KI bitten, Konfiguration zu generieren
Verwenden Sie einen Prompt wie diesen im GitHub Copilot Chat oder einem anderen KI-Assistenten:
Erstelle eine [tool.ruff] Konfiguration für pyproject.toml mit:
- Zeilenlänge: 88
- Ziel Python 3.12
- Ausschließen: .git, .venv, __pycache__, build, dist
- Diese Regelgruppen aktivieren: pycodestyle (E/W), Pyflakes (F), isort (I),
pep8-naming (N), flake8-bugbear (B), flake8-comprehensions (C4), pyupgrade (UP)
- Auto-Fix für alle Regeln erlauben
- Formatierung mit doppelten Anführungszeichen, Unix-Zeilenenden, Leerzeichen-Einrückung
Schritt 3: Überprüfen und anwenden
Die KI generiert die Konfiguration. Überprüfen Sie sie immer - Sie sind der Experte für Ihre Projektanforderungen:
[project]
name = "road-profile-viewer"
version = "0.1.0"
description = "Interactive road profile visualization"
requires-python = ">=3.12"
[tool.ruff]
# Maximale Zeilenlänge festlegen
line-length = 88
# Ziel-Python-Version
target-version = "py312"
# Bestimmte Verzeichnisse ausschließen
exclude = [
".git",
".venv",
"__pycache__",
"build",
"dist",
]
[tool.ruff.lint]
# Regeln zum Aktivieren auswählen
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort (import sorting)
"N", # pep8-naming
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
# Spezifische Regeln ignorieren, falls nötig
ignore = []
# Auto-Fix für diese Regeln erlauben
fixable = ["ALL"]
unfixable = []
[tool.ruff.format]
# Doppelte Anführungszeichen verwenden (wie Black)
quote-style = "double"
# Unix-Zeilenenden verwenden
line-ending = "lf"
# Mit Leerzeichen einrücken
indent-style = "space"
Warum dieser Ansatz funktioniert:
✅ Fokus auf Absicht - Sie spezifizieren was Sie wollen, nicht wie man es schreibt
✅ Schnellere Entwicklung - Kein Nachschlagen exakter Konfigurationsschlüssel
✅ Lernen durch Überprüfung - Sie sehen korrekte Syntax und können sie anpassen
✅ Syntaxfehler vermeiden - KI kennt die exakte TOML-Struktur
Merke: KI ist Ihr Syntax-Assistent, aber SIE entscheiden die Anforderungen basierend auf Ihren Projektbedürfnissen!
8.6 Ruff in VS Code - Echtzeit-Feedback
Während Ruff über die Kommandozeile mächtig ist, bringt die Ruff VS Code-Erweiterung Code-Qualität direkt in Ihren Editor mit sofortigem Feedback beim Tippen.
8.6.1 Installation der Ruff-Erweiterung
Methode 1: VS Code Extensions-Panel
- Öffnen Sie VS Code
- Klicken Sie auf das Extensions-Icon (oder drücken Sie
Strg+Umschalt+X/Cmd+Shift+X) - Suchen Sie nach “Ruff”
- Klicken Sie auf Installieren bei der offiziellen Erweiterung von Astral
Methode 2: Kommandozeile
code --install-extension charliermarsh.ruff
Methode 3: Quick Open
- Drücken Sie
Strg+P/Cmd+P - Geben Sie ein:
ext install charliermarsh.ruff - Drücken Sie Enter
8.6.2 Echtzeit-Linting - Sofortiges Feedback
Nach der Installation analysiert Ruff Ihren Code automatisch während Sie tippen und zeigt Probleme mit farbigen Unterstreichungen:
Rote Wellenlinien = Fehler (müssen behoben werden)
import sys,os # Rote Unterstreichung: E401 Mehrere Imports auf einer Zeile
Gelbe Wellenlinien = Warnungen (sollten behoben werden)
def HelperFunction(val): # Gelbe Unterstreichung: N802 Funktionsname sollte Kleinbuchstaben sein
Hover für Details:
- Bewegen Sie die Maus über unterstriche Code
- Ein Popup zeigt:
- Regelcode (z.B.
E401) - Beschreibung der Verletzung
- Quick Fix-Button, falls automatisch behebbar
- Regelcode (z.B.
Problems-Panel:
- Drücken Sie
Strg+Umschalt+M/Cmd+Shift+Mzum Öffnen des Problems-Panels - Sehen Sie alle Probleme über alle Dateien hinweg
- Klicken Sie auf ein Problem, um zu dieser Zeile zu springen
- Filtern Sie nach Fehlern, Warnungen oder Informationen
Vorteile:
- Probleme sofort erkennen - Keine Kommandos ausführen nötig
- Lernen während Sie codieren - Erklärungen für Verstöße sehen
- Kontextbezogen - Zeigt nur relevante Probleme für Ihre Datei
- Team-Konsistenz - Jeder sieht dieselben Probleme im Editor
8.6.3 Auto-Fix mit Tastaturkürzeln
Die Ruff-Erweiterung kann viele Probleme automatisch beheben, ohne den Editor zu verlassen.
Quick Fix (Einzelnes Problem):
- Platzieren Sie Cursor auf unterstrichenem Code
- Drücken Sie
Strg+./Cmd+.(oder klicken Sie auf das Glühbirnen-Icon 💡) - Wählen Sie “Ruff: Fix all auto-fixable problems”
- Problem ist sofort behoben!
Beispiel:
# Vorher (Cursor auf dieser Zeile)
import sys,os,json # E401-Verletzung
# Drücken Sie Strg+. und wählen Sie Fix
# Nachher
import sys
import os
import json
Dokument formatieren (Alles auto-formatieren):
- Drücken Sie
Umschalt+Alt+F/Shift+Option+F - Oder Rechtsklick → “Dokument formatieren”
- Ruff formatiert die gesamte Datei gemäß Ihren Stilregeln
Auswahl formatieren:
- Wählen Sie spezifischen Code aus
- Drücken Sie
Strg+K Strg+F/Cmd+K Cmd+F - Nur der ausgewählte Code wird formatiert
Alle automatisch behebbaren Probleme beheben:
- Öffnen Sie Command Palette:
Strg+Umschalt+P/Cmd+Shift+P - Geben Sie ein: “Ruff: Fix all auto-fixable problems”
- Drücken Sie Enter
- Alle automatisch behebbaren Probleme in der aktuellen Datei werden behoben
8.6.4 Format on Save - Null Aufwand
Konfigurieren Sie VS Code, um automatisch zu formatieren und Probleme zu beheben, wenn Sie eine Datei speichern.
Format on Save aktivieren:
- Öffnen Sie Einstellungen:
Strg+,/Cmd+, - Suchen Sie nach:
format on save - Aktivieren Sie ✅ Editor: Format On Save
Ruff als Standard-Formatter konfigurieren:
Fügen Sie zu Ihrer .vscode/settings.json hinzu (in Ihrem Projekt):
{
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
}
Was das bewirkt:
- formatOnSave: Führt
ruff formatbeim Speichern aus - fixAll.ruff: Behebt automatisch alle behebbaren Probleme
- organizeImports.ruff: Sortiert und organisiert Imports
Ergebnis: Drücken Sie Strg+S / Cmd+S → Code ist sofort formatiert und bereinigt! 🎉
8.6.5 Praktisches Workflow-Beispiel
Szenario: Sie schreiben neuen Code mit mehreren PEP 8-Verletzungen.
Ohne VS Code-Erweiterung:
# Sie schreiben diesen Code
def ProcessData(input,threshold=10):
result=[]
for item in input:
if item>threshold:result.append(item*2)
return result
# Später führen Sie Kommandozeile aus
$ uv run ruff check main.py
# Sehen 8 Verletzungen
# Manuell beheben oder --fix verwenden
# Erneut ausführen zur Überprüfung
Mit VS Code-Erweiterung:
# Während Sie tippen, sehen Sie:
def ProcessData(input,threshold=10): # Gelbe Unterstreichung: N802
# ^ Gelbe Unterstreichung: E231
result=[] # Gelbe Unterstreichung: E225
# ^
for item in input:
if item>threshold:result.append(item*2)
# ^E225 ^E701 zusammengesetzte Anweisung
# Sie drücken Strg+. auf Funktionsnamen → Quick fix "Kleinbuchstaben verwenden"
# Sie drücken Umschalt+Alt+F → Gesamtes Dokument formatieren
# Ergebnis (sofort):
def process_data(input, threshold=10):
result = []
for item in input:
if item > threshold:
result.append(item * 2)
return result
# Alle Verletzungen in 2 Sekunden behoben! 🚀
8.6.6 Konfigurations-Tipps
Workspace-Einstellungen (Projektspezifisch)
Erstellen Sie .vscode/settings.json in Ihrem Projekt:
{
"ruff.lint.args": ["--config=pyproject.toml"],
"ruff.format.args": ["--config=pyproject.toml"],
"ruff.organizeImports": true,
"ruff.fixAll": true,
"editor.rulers": [88],
"files.trimTrailingWhitespace": true
}
Benutzereinstellungen (Alle Projekte)
Einstellungen → Suche “ruff” → Konfigurieren:
- ✅ Ruff: Enable (Standard: true)
- ✅ Ruff: Organize Imports
- ✅ Ruff: Fix All
- Setzen Sie Ruff: Path, falls Sie eine benutzerdefinierte Ruff-Installation verwenden
Konflikt-Erweiterungen deaktivieren:
Falls Sie diese installiert haben, deaktivieren Sie sie für Python-Dateien:
- Pylint
- Flake8
- Black formatter
- autopep8
Sie kollidieren mit Ruff und verlangsamen Ihren Editor.
8.6.7 Fehlersuche
Problem: Ruff-Erweiterung funktioniert nicht
✅ Lösung:
- Prüfen Sie, ob Erweiterung installiert ist:
Strg+Umschalt+X→ Suche “Ruff” - Prüfen Sie, ob Erweiterung für Workspace aktiviert ist
- VS Code neu laden:
Strg+Umschalt+P→ “Reload Window” - Prüfen Sie Output-Panel: Ansicht → Output → “Ruff” auswählen
Problem: Format on save funktioniert nicht
✅ Lösung:
- Überprüfen Sie settings.json-Konfiguration
- Prüfen Sie, ob Ruff Standard-Formatter ist:
Strg+Umschalt+P→ “Dokument formatieren mit…” → “Ruff” auswählen - Datei speichern und Problems-Panel auf Fehler prüfen
Problem: Zu viele Warnungen
✅ Lösung:
- Konfigurieren Sie
pyproject.toml, um spezifische Regeln zu ignorieren - Schweregrad anpassen: Einstellungen → Suche “ruff” → Schweregradebene festlegen
- Verwenden Sie
# noqa-Kommentare für spezifische Zeilen (sparsam!)
import sys # noqa: F401 - benötigt für Debugging
8. Teil 6: Type Checking mit Pyright
8.1 Warum Type Checking wichtig ist
Python ist dynamisch typisiert, was flexibel, aber gefährlich ist:
def calculate_discount(price, discount_percent):
return price * (discount_percent / 100)
# Das wird zur Laufzeit abstürzen!
result = calculate_discount("50", "10")
Type Hints (Python 3.5+) erlauben es Ihnen, Typ-Informationen hinzuzufügen:
def calculate_discount(price: float, discount_percent: float) -> float:
return price * (discount_percent / 100)
# Type Checker fängt dies VOR der Laufzeit
result = calculate_discount("50", "10") # Fehler: Erwartete float, bekam str
8.2 Was ist Pyright?
Pyright ist ein schneller, funktionsreicher Type Checker für Python, entwickelt von Microsoft.
Warum Pyright statt mypy?
| Merkmal | Pyright | mypy |
|---|---|---|
| Geschwindigkeit | 5-10x schneller (TypeScript/Node.js) | Langsamer (Python-basiert) |
| VS Code Integration | In Pylance-Extension eingebaut | Separate Extension benötigt |
| Modernes Python | Exzellente 3.10+ Unterstützung | Gute Unterstützung, langsamere Updates |
| Type Inference | Intelligenter | Gut, aber weniger ausgeklügelt |
| Aktive Entwicklung | Microsoft-unterstützt, schnelle Updates | Langsamerer Update-Zyklus |
Für diesen Kurs: Wir verwenden Pyright, weil es zu Ihrer IDE (VS Code + Pylance) passt und eine konsistente Erfahrung bietet.
8.3 Pyright installieren
Genau wie Ruff sollte Pyright als Entwicklungs-Abhängigkeit installiert werden:
uv add --dev pyright
Dies fügt Pyright zu [dependency-groups.dev] in Ihrer pyproject.toml hinzu:
[dependency-groups]
dev = [
"ruff",
"pyright",
]
Synchronisieren und verifizieren:
# Entwicklungs-Abhängigkeiten installieren
uv sync --group dev
# Pyright testen
uv run pyright --version
8.3.1 Windows-Setup: Entwicklermodus erforderlich
⚠️ Windows-spezifisches Problem:
Pyright ist ein TypeScript-basiertes Tool, das Node.js benötigt. Wenn Sie uv run pyright zum ersten Mal ausführen, installiert uv automatisch Node.js (v25.0.0+) und erstellt Symlinks.
Unter Windows sehen Sie möglicherweise diesen Fehler:
Error: You do not have sufficient permissions to perform this operation.
Warum? Das Erstellen von Symlinks unter Windows erfordert entweder:
- Administrator-Rechte, ODER
- Entwicklermodus aktiviert (empfohlen)
Lösung: Windows-Entwicklermodus aktivieren
Führen Sie PowerShell als Administrator aus und führen Sie dann aus:
# Entwicklermodus aktivieren (erfordert Admin-Rechte)
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
Nach Ausführung dieses Befehls:
- Starten Sie Ihr Terminal neu
- Versuchen Sie erneut
uv run pyright --version - Node.js wird automatisch installiert und Pyright funktioniert
Alternative (nicht empfohlen): VS Code jedes Mal als Administrator ausführen. Entwicklermodus ist besser, da es eine einmalige Einrichtung ist.
8.4 Pyright konfigurieren - Von nachsichtig zu strikt
8.4.1 Das Standard-Problem
Standardmäßig läuft Pyright im Basic-Modus - es ist sehr nachsichtig und fängt viele Type-Probleme nicht:
uv run pyright
# Ausgabe: 0 errors found in 5 files
Das scheint gut, ist aber irreführend! Pyright ignoriert:
- Fehlende Type Hints
- Implizite
Any-Typen - Ungenutzte Variablen
- Nicht-typisierte Funktionsrückgaben
Warum so nachsichtig? Um mit bestehenden Python-Codebasen zu arbeiten, die keine Type Hints haben.
Für neue Projekte: Wir wollen strengere Prüfung, um Probleme früh zu fangen.
8.4.2 KI nutzen für strikte Type-Checking-Konfiguration
Definieren Sie Ihre Anforderungen:
Für unser Kursprojekt wollen wir:
- Strikte Type-Checking-Modus
- Ziel Python 3.12
- Alle
.py-Dateien imsrc/-Verzeichnis prüfen - Fehlende Type Hints melden
- Häufige Type-Safety-Probleme fangen
Prompt für KI:
Erstelle eine [tool.pyright] Konfiguration für pyproject.toml mit:
- Type-Checking-Modus: strict
- Python-Version: 3.12
- Include: src Verzeichnis
- Report missing type stubs: true
- Report unknown member type: warning
- Report unknown parameter type: warning
- Report unknown variable type: warning
Generierte Konfiguration:
Fügen Sie dies zu Ihrer pyproject.toml hinzu:
[tool.pyright]
# Strikte Type-Prüfung
typeCheckingMode = "strict"
# Python-Version
pythonVersion = "3.12"
# Nur Source-Dateien einschließen
include = ["src"]
# Verzeichnisse ausschließen
exclude = [
".venv",
"__pycache__",
"build",
"dist",
]
# Reporting-Optionen
reportMissingTypeStubs = true
reportUnknownMemberType = "warning"
reportUnknownParameterType = "warning"
reportUnknownVariableType = "warning"
reportUnknownArgumentType = "warning"
Jetzt Pyright erneut ausführen:
uv run pyright
Sie werden wahrscheinlich viele Fehler sehen! Das ist gut - dies waren versteckte Probleme, die Pyright jetzt fängt.
Häufige Fehler, die Sie sehen werden:
src/main.py:10:5 - error: Type of "x" is unknown (reportUnknownVariableType)
src/utils.py:25:15 - error: Return type is unknown (reportUnknownParameterType)
Type-Checking-Modi erklärt:
| Modus | Strenge | Anwendungsfall |
|---|---|---|
off |
Keine Prüfung | Legacy-Code, Prototypen |
basic |
Minimal (Standard) | Schrittweise Typisierung |
standard |
Moderat | Die meisten Projekte |
strict |
Maximum | Neue Projekte, hohe Qualität |
Für diesen Kurs: Verwenden Sie den strict-Modus, um von Anfang an ordnungsgemäße Type Safety zu lernen.
8.5 Type Hints verwenden
Grundtypen:
# Variablen
name: str = "Alice"
age: int = 25
height: float = 1.75
is_student: bool = True
# Funktionen
def greet(name: str) -> str:
return f"Hello, {name}"
def calculate_total(items: list[float]) -> float:
return sum(items)
Optionale Typen (None-Behandlung):
def find_user(user_id: int) -> User | None:
"""Gibt User zurück oder None, wenn nicht gefunden."""
...
user = find_user(123)
# Pyright-Fehler: 'user' könnte None sein
print(user.name)
# Richtige Art
if user is not None:
print(user.name)
Komplexe Typen:
from typing import Callable
# Funktion, die einen Callback nimmt
def process(callback: Callable[[int], str]) -> None:
result = callback(42)
print(result)
# Richtiger Callback
def my_callback(x: int) -> str:
return f"Value: {x}"
process(my_callback) # OK
# Falscher Callback
def wrong_callback(x: str) -> str:
return f"Value: {x}"
process(wrong_callback) # Pyright-Fehler: Signatur passt nicht
Typen auf Road Profile Viewer anwenden:
import numpy as np
from numpy.typing import NDArray
def generate_road_profile(
num_points: int = 100,
x_max: float = 80
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
"""
Generiert ein Straßenprofil mit einer Klothoiden-ähnlichen Approximation.
Args:
num_points: Anzahl der zu generierenden Punkte
x_max: Maximaler x-Koordinatenwert
Returns:
Tupel von (x_koordinaten, y_koordinaten)
"""
x = np.linspace(0, x_max, num_points)
x_norm = x / x_max
y = 0.015 * x_norm**3 * x_max + 0.3 * np.sin(2 * np.pi * x_norm)
y = y - y[0]
return x, y
def find_intersection(
x_road: NDArray[np.float64],
y_road: NDArray[np.float64],
angle_degrees: float,
camera_x: float = 0,
camera_y: float = 1.5
) -> tuple[float, float, float] | tuple[None, None, None]:
"""
Findet Schnittpunkt zwischen Kamerastrahl und Straßenprofil.
Args:
x_road: X-Koordinaten des Straßenprofils
y_road: Y-Koordinaten des Straßenprofils
angle_degrees: Kamerastrahlwinkel in Grad
camera_x: Kamera-X-Position
camera_y: Kamera-Y-Position
Returns:
Tupel von (x_intersect, y_intersect, distance) oder (None, None, None)
"""
# Implementierung...
pass
8.6 Pyright ausführen
Nach Installation und Konfiguration prüfen Sie Ihren Code auf Type-Fehler:
# Alle Dateien prüfen (berücksichtigt pyproject.toml-Konfiguration)
uv run pyright
# Spezifische Datei prüfen
uv run pyright src/main.py
# Detaillierte Fehlerinformationen anzeigen
uv run pyright --verbose
Was Sie im strict-Modus erwarten sollten:
- Zunächst viele Fehler (fehlende Type Hints, unbekannte Typen)
- Das ist gut - Sie fangen Probleme früh
- Type Hints schrittweise hinzufügen, um Fehler zu beheben
- Ihr Code wird robuster und wartbarer
Beispiel-Workflow:
# 1. Pyright ausführen
uv run pyright
# 2. Gemeldete Type-Probleme in Ihrem Code beheben
# 3. Erneut ausführen zur Verifizierung
uv run pyright
# Alles klar!
# ✓ 0 errors found in 5 files
9. Zusammenfassung: Von Tools zur Praxis
9.1 Funktionierender Code ≠ Qualitätscode
Code, der läuft, ist erst der Anfang. Professionelle Software muss sein:
- Lesbar - Einfach für Menschen zu verstehen
- Wartbar - Einfach zu modifizieren und zu erweitern
- Konsistent - Folgt Team- und Community-Standards
- Typsicher - Fängt Fehler vor der Laufzeit
9.2 Die Tools, die Sie brauchen
Für Qualitätsdurchsetzung:
- Ruff - Schneller Linter und Formatter (ersetzt Flake8, Black, isort)
- Pyright - Type Checker, integriert in VS Code
Checks lokal ausführen:
uv run ruff check --fix .
uv run ruff format .
uv run pyright
9.3 Folgen Sie PEP 8
Pythons Style Guide ist nicht optional:
- Lernen Sie die Schlüsselregeln (Abstände, Benennung, Zeilenlänge)
- Verwenden Sie Tools, die PEP 8 automatisch durchsetzen
- Vertrauen Sie dem Formatter, um Style konsistent zu machen
9.4 Type Hints sparen Zeit
Type Hints fangen Bugs, bevor sie die Produktion erreichen:
- Beginnen Sie mit Funktionssignaturen
- Verwenden Sie
|für Union-Typen (z.B.str | None) - Lassen Sie Pyright Typ-Nichtübereinstimmungen fangen
- Ihr zukünftiges Ich wird Ihnen danken
9.5 Was kommt als Nächstes?
Sie wissen jetzt was zu prüfen ist und wie man es lokal prüft. Aber wie stellen Sie sicher, dass diese Checks automatisch bei jedem Commit laufen und verhindern, dass schlechter Code in Ihr Repository gelangt?
In Kapitel 02 (Feature-Entwicklung) (Donnerstag, 16. Oktober) werden wir erkunden:
- Continuous Integration/Continuous Deployment (CI/CD) - Was es ist und warum es wichtig ist
- GitHub Actions - GitHubs Automatisierungsplattform
- Automatisierte Workflows - Qualitätschecks bei jedem Push ausführen
- Pre-commit Hooks - Lokale Qualitätstore, bevor Code GitHub erreicht
- Branch Protection - Qualitätsstandards vor dem Merge durchsetzen
Wir werden Ihre lokalen Qualitätschecks in eine automatisierte Pipeline verwandeln, die Qualität 24/7 durchsetzt und sicherstellt, dass jeder Commit Ihre Standards erfüllt, egal ob Sie sich daran erinnern, die Checks auszuführen oder nicht.
10. Die Qualitätslandschaft verstehen: Konzepte und Tools
Bevor wir uns in die praktische Aufgabe vertiefen, lassen Sie uns die verschiedenen Qualitätskonzepte klären, die wir besprochen haben, und wie sie sich zueinander verhalten. Diese Landschaft kann verwirrend sein, weil sich einige Konzepte überschneiden und die Tools, die wir verwenden (Ruff und Pyright), mehrere Aspekte der Qualität behandeln.
10.1 Die Qualitätskonzepte
10.1.1 Style Guide (PEP 8)
Was es ist: Ein Dokument, das Codierungskonventionen definiert—die “Grammatikregeln” des Python-Codes.
Was es abdeckt:
- Code-Layout (Einrückung, Zeilenlänge, Leerzeilen)
- Namenskonventionen (Funktionen, Klassen, Variablen)
- Import-Organisation
- Leerzeichenverwendung
- Kommentarstil
Pythons Realisierung: PEP 8 ist Pythons offizieller Style Guide, geschrieben von Guido van Rossum und der Python-Community.
Analogie: Wie ein Sprachstil-Leitfaden (APA, MLA, Chicago) für das Schreiben von Aufsätzen—er sagt Ihnen die “richtige” Art, Ihren Code zu formatieren.
Beispielregel:
“Funktionsnamen sollten Kleinbuchstaben mit durch Unterstriche getrennten Wörtern sein” → calculate_total() nicht CalculateTotal()
10.1.2 Linting
Was es ist: Automatisierte Analyse von Code, um Fehler, Bugs, stilistische Probleme und verdächtige Konstrukte zu finden.
Was es abdeckt:
- Style-Verstöße (Abstände, Benennung, Imports) ← überschneidet sich mit Style Guide
- Potenzielle Bugs (ungenutzte Variablen, undefinierte Namen)
- Code-Smells (überkomplizierter Code, doppelter Code)
- Best Practices (Anti-Patterns, veraltete Syntax)
Pythons Realisierung mit Ruff:
ruff check analysiert Ihren Code gegen 800+ Regeln, einschließlich PEP 8-Style-Regeln, gängiger Bug-Muster und Best Practices.
Analogie: Wie ein Grammatikchecker in Microsoft Word—er hebt Probleme hervor und schlägt Fixes vor.
Beispiel-Checks:
E501: Zeile zu lang (Style-Problem)F401: Ungenutzter Import (potenzieller Bug)B008: Führen Sie keine Funktionsaufrufe in Argument-Defaults aus (fehleranfälliges Muster)
Wichtige Erkenntnis: Linting ist der Prozess der Code-Prüfung. PEP 8 ist einer der Standards, die geprüft werden. Linters prüfen auf PEP 8-Konformität UND viel mehr.
10.1.3 Formatierung
Was es ist: Automatische Umstrukturierung von Code, um konsistenten Style-Regeln zu folgen—eine Teilmenge dessen, was ein Linter prüft.
Was es abdeckt:
- Leerzeichen (Leerzeichen um Operatoren, nach Kommas)
- Einrückung (konsistente Tab/Leerzeichen-Verwendung)
- Zeilenumbrüche (wo lange Zeilen umgebrochen werden)
- Anführungszeichenstil (einfache vs. doppelte Anführungszeichen)
Pythons Realisierung mit Ruff:
ruff format formatiert Ihren Code automatisch, um PEP 8-konform zu sein (Black-kompatibler Style).
Analogie: Wie “Auto-Format” in Word—es behebt Abstände und Layout automatisch.
Wichtiger Unterschied:
- Linter (
ruff check): Findet Probleme und meldet sie - Formatter (
ruff format): Behebt Style-Probleme automatisch
Beispiel:
# Vorher
x=1+2
# Linter sagt: "E225: Fehlendes Leerzeichen um Operator"
# Formatter behebt es automatisch:
x = 1 + 2
10.1.4 Type Hints
Was es ist: Optionale Annotationen, die spezifizieren, welche Arten von Werten Variablen, Parameter und Rückgabewerte haben sollten.
Was es abdeckt:
- Funktionssignaturen (Parametertypen, Rückgabetypen)
- Variablenannotationen
- Komplexe Typen (Listen, Dicts, Unions, Optionals)
Pythons Realisierung:
In Python 3.5+ eingebaut, unter Verwendung des typing-Moduls. Von Entwicklern zum Code hinzugefügt.
Syntax:
def calculate_total(prices: list[float]) -> float:
return sum(prices)
Analogie: Wie das Deklarieren von Variablentypen in statisch typisierten Sprachen (Java, C++), aber optional in Python.
Wichtige Erkenntnis: Type Hints sind Annotationen, die Sie schreiben. Sie tun von sich aus nichts—Sie benötigen einen Type Checker, um sie zu validieren.
10.1.5 Type Checking
Was es ist: Automatisierte Analyse, die überprüft, ob Type Hints konsistent und korrekt in Ihrem Code verwendet werden.
Was es abdeckt:
- Erkennung von Typ-Nichtübereinstimmungen (String übergeben, wo int erwartet)
- Finden fehlender Typ-Annotationen
- Validierung von Funktionsaufrufsignaturen
- Fangen von
None-Behandlungsfehlern
Pythons Realisierung mit Pyright:
pyright analysiert Ihre Type Hints und leitet Typen ab, auch wo nicht explizit annotiert.
Analogie: Wie ein Compiler-Type-Checker in Java oder TypeScript—fängt Typfehler vor der Laufzeit.
Beispiel:
def greet(name: str) -> str:
return f"Hello, {name}"
result = greet(42) # Pyright-Fehler: Argument vom Typ 'int' kann nicht dem Parameter 'str' zugewiesen werden
Wichtiger Unterschied:
- Type Hints: Annotationen, die Sie schreiben
- Type Checking: Tool, das diese Annotationen validiert
10.2 Wie sich die Konzepte überschneiden
Hier passiert oft Verwirrung:
┌─────────────────────────────────────────────────────────────┐
│ PEP 8 │
│ (Der Style Guide - Die Regeln) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Linting (ruff check) │ │
│ │ │ │
│ │ • Prüft PEP 8-Style-Regeln ←───────────────────────────── Überschneidung!
│ │ • Prüft auf Bugs (ungenutzte Imports, undefinierte Vars)│
│ │ • Prüft Best Practices (Anti-Patterns) │ │
│ │ • Prüft Code-Smells │ │
│ │ │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Formatierung (ruff format) │ │ │
│ │ │ │ │ │
│ │ │ • Behebt Style-Probleme automatisch ←───────┼─────┼───── Teilmenge!
│ │ │ • Leerzeichen, Einrückung, Anführungszeichen│ │
│ │ └──────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Typsystem (Separat!) │
│ │
│ Sie schreiben: Tool validiert: │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ Type Hints │ ──→ │ Type Checking │ │
│ │ (Annotationen) │ │ (pyright) │ │
│ └─────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Wichtige Überschneidungen:
- Linting beinhaltet Style-Checking
ruff checkvalidiert PEP 8-Style-Regeln- Aber es prüft auch auf Bugs und Best Practices, die PEP 8 nicht abdeckt
- Formatierung ist eine Teilmenge von Linting
- Beide befassen sich mit Code-Style
- Formatter behebt automatisch, Linter meldet
- Formatter behandelt nur Layout/Leerzeichen, Linter prüft auch Logik
- Type Hints werden von Lintern UND Type Checkern geprüft
ruff checkkann fehlende Type Hints finden (wenn konfiguriert)pyrightvalidiert, dass Type Hints korrekt verwendet werden- Verschiedene Tools, komplementäre Zwecke
10.3 Die Python-Realisierungen: Ruff und Pyright
10.3.1 Ruff: Das Multi-Tool
Ruff kombiniert mehrere Qualitätschecks:
| Befehl | Was es tut | Welches Konzept | Beispiel |
|---|---|---|---|
ruff check |
Linting | Style Guide + Bug-Erkennung | Findet E501 (Zeile zu lang), F401 (ungenutzter Import) |
ruff format |
Formatierung | Style Guide-Durchsetzung | Behebt Abstände: x=1 → x = 1 |
ruff check --select I |
Import-Sortierung | Style Guide (PEP 8 Imports) | Organisiert Imports alphabetisch |
Warum das verwirrend ist: Ruff macht Linting UND Formatierung, was traditionell separate Tools waren (Flake8 + Black). Jetzt ist es ein Tool mit zwei Modi.
Mentales Modell:
ruff check= “Sag mir, was falsch ist”ruff format= “Behebe den Style für mich”ruff check --fix= “Sag mir, was falsch ist UND behebe, was Sie können”
10.3.2 Pyright: Die Typ-Polizei
Pyright konzentriert sich auf Typ-Korrektheit:
| Was es tut | Welches Konzept | Beispiel |
|---|---|---|
| Validiert Type Hints | Type Checking | Fängt greet(42), wenn Signatur greet(name: str) ist |
| Leitet Typen ab | Type Checking | Weiß x = 5 bedeutet x: int auch ohne Annotation |
Findet None-Probleme |
Type Checking | Fängt user.name, wenn user möglicherweise None ist |
| Meldet fehlende Typen | Code-Qualität | Warnt, wenn Funktionen Typ-Annotationen fehlen |
Warum sowohl Ruff ALS AUCH Pyright verwenden?
- Ruff: Style, Imports, Bugs, allgemeine Code-Qualität
- Pyright: Typ-Sicherheit, Fangen typbezogener Bugs
Sie ergänzen sich—das eine ersetzt nicht das andere.
10.4 Ihr Qualitäts-Workflow
Schritt-für-Schritt was passiert:
# 1. Sie schreiben Code (mit Type Hints)
def calculate_total(prices: list[float]) -> float:
x=sum(prices) # Hoppla, fehlende Leerzeichen
return x
# 2. Formatter ausführen
$ uv run ruff format .
→ Behebt Abstände automatisch: x = sum(prices)
# 3. Linter ausführen
$ uv run ruff check .
→ Prüft PEP 8-Konformität ✓
→ Prüft auf Bugs ✓
→ Prüft Best Practices ✓
# 4. Type Checker ausführen
$ uv run pyright
→ Validiert, dass Type Hints korrekt verwendet werden ✓
→ Leitet Typen ab und fängt Nichtübereinstimmungen ✓
Jedes Tool hat eine spezifische Aufgabe:
- Formatter (
ruff format): Macht Code konsistent aussehend - Linter (
ruff check): Findet Style-Probleme + Bugs + Code-Smells - Type Checker (
pyright): Validiert Typ-Sicherheit
10.5 Häufige Verwirrung geklärt
F: “Ist Linting dasselbe wie PEP 8-Prüfung?” A: Nein. Linting beinhaltet PEP 8-Checks, prüft aber auch auf Bugs, Best Practices und Code-Smells. PEP 8 ist nur ein Standard, gegen den Linters prüfen.
F: “Brauche ich sowohl ruff check als auch ruff format?”
A: Ja! Sie dienen unterschiedlichen Zwecken:
ruff format: Behebt Style automatisch (Abstände, Einrückung)ruff check: Meldet Bugs, ungenutzten Code und Probleme, die nicht automatisch behoben werden können
F: “Warum brauche ich Pyright, wenn Ruff Code-Qualität prüft?” A: Ruff prüft Style und allgemeine Bugs. Pyright prüft Typ-Sicherheit. Beispiel:
def greet(name: str) -> str:
return f"Hello, {name}"
result = greet(42) # Ruff wird das nicht fangen, Pyright schon!
F: “Kann Ruff alles automatisch beheben?”
A: Nein. ruff format behebt Style. ruff check --fix behebt einige Probleme (wie ungenutzte Imports). Aber logische Bugs und Benennungsverstöße brauchen manuelle Fixes.
F: “Sind Type Hints erforderlich?” A: Nein, Python funktioniert ohne sie gut. Aber sie:
- Fangen Bugs vor der Laufzeit
- Verbessern IDE-Auto-Complete
- Dienen als Dokumentation
- Machen Code wartbarer
F: “Wenn ich PEP 8 befolge, warum brauche ich dann Tools?” A: Menschen machen Fehler und übersehen Dinge. Tools:
- Vergessen nie eine Regel
- Prüfen Hunderte Regeln in Sekunden
- Sind konsistent im gesamten Team
- Befreien Menschen, sich auf Logik zu konzentrieren, nicht auf Style
10.6 Das vollständige Bild
Der Qualitäts-Stack für Python in 2025:
┌───────────────────────────────────────────┐
│ Entwickler schreibt Code │
│ (mit Type Hints) │
└─────────────────┬─────────────────────────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
┌───────────────┐ ┌──────────────────┐
│ Ruff │ │ Pyright │
│ │ │ │
│ • Prüft Style │ │ • Prüft Typen │
│ • Format Code │ │ • Leitet Typen ab│
│ • Findet Bugs │ │ • Findet None- │
│ • Best Pract. │ │ Probleme │
└───────────────┘ └──────────────────┘
│ │
└─────────┬─────────┘
│
▼
┌─────────────────┐
│ Qualitätscode │
│ │
│ ✓ PEP 8 │
│ ✓ Weniger Bugs │
│ ✓ Typsicher │
│ ✓ Konsistent │
└─────────────────┘
Zusammenfassung in einem Satz: Wir verwenden PEP 8 als unseren Style Guide, Ruff um ihn durchzusetzen und Bugs zu fangen, und Pyright um Typ-Sicherheit zu gewährleisten—drei komplementäre Schichten der Qualitätssicherung.
11. Praktische Aufgabe
11.1 Aufgabe: Road Profile Viewer reparieren
Lassen Sie uns alle Probleme in unserer main.py-Datei Schritt für Schritt beheben.
11.2 Schritt 1: Ungenutzte Imports entfernen
Vorher:
import sys,os # Mehrere Imports, beide ungenutzt
Nachher:
# Entfernt - nicht benötigt
11.3 Schritt 2: Import-Formatierung beheben
Vorher:
import numpy as np
from dash import Dash, html, dcc, Input, Output
import plotly.graph_objects as go
Nachher:
import numpy as np
from numpy.typing import NDArray
from dash import Dash, Input, Output, dcc, html
import plotly.graph_objects as go
Beachten Sie:
- Imports nach Kategorie gruppiert (Standardbibliothek, Drittanbieter)
- Alphabetisch sortiert innerhalb der Gruppen
numpy.typingfür Type Hints hinzugefügt
11.4 Schritt 3: Funktionsabstände beheben
Vorher:
def generate_road_profile(num_points=100,x_max=80):
y=0.015 * x_norm**3 * x_max
return x,y
Nachher:
def generate_road_profile(num_points=100, x_max=80):
y = 0.015 * x_norm**3 * x_max
return x, y
11.5 Schritt 4: Type Hints hinzufügen
Vorher:
def generate_road_profile(num_points=100, x_max=80):
"""Generate a road profile using a clothoid-like approximation."""
# ...
return x, y
Nachher:
def generate_road_profile(
num_points: int = 100,
x_max: float = 80
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
"""
Generiert ein Straßenprofil mit einer Klothoiden-ähnlichen Approximation.
Args:
num_points: Anzahl der zu generierenden Punkte
x_max: Maximaler x-Koordinatenwert
Returns:
Tupel von (x_koordinaten, y_koordinaten) als NumPy-Arrays
"""
# ...
return x, y
11.6 Schritt 5: Namenskonvention beheben
Vorher:
def HelperFunction(val):
result=val*2
return result
Nachher:
# Entfernt - Funktion war ungenutzter toter Code
11.7 Schritt 6: Variablenabstände beheben
Vorher:
camera_x,camera_y = 0,2.0
marker=dict(size=12,color='red',symbol='circle')
Nachher:
camera_x, camera_y = 0, 2.0
marker = dict(size=12, color='red', symbol='circle')
11.8 Schritt 7: Lange Zeilen beheben
Vorher:
# Add camera ray - This is a very long comment that exceeds the recommended 79 character line length limit specified in PEP8 style guide
Nachher:
# Füge Kamerastrahl zum Plot hinzu
# Dies zeigt die Linie von der Kamera in Richtung des angegebenen Winkels
11.9 Checks nach Fixes ausführen
$ uv run ruff check .
All checks passed!
$ uv run ruff format --check .
All files formatted correctly!
$ uv run pyright
0 errors, 0 warnings, 0 informations
Erfolg! 🎉
12. Teil 9: Der Business Case für Code-Qualität
12.1 Warum sich Unternehmen für Code-Qualität interessieren
1. Schnellere Entwicklung
- Sauberer Code ist einfacher zu modifizieren
- Weniger Zeit für Debugging
- Schnelleres Onboarding für neue Entwickler
2. Weniger Bugs
- Automatisierte Checks fangen Probleme früh
- Type Checking verhindert Laufzeitfehler
- Konsistenter Code reduziert Verwirrung
3. Niedrigere Wartungskosten
- Gut strukturierter Code hält länger
- Einfacher, Abhängigkeiten zu aktualisieren
- Reduzierte technische Schuld
4. Bessere Zusammenarbeit
- Konsistenter Style beseitigt Reibung
- Klarer Code reduziert Missverständnisse
- Automatisierte Checks eliminieren Style-Debatten
5. Wettbewerbsvorteil
- Schneller Features ausliefern
- Höhere Produktqualität
- Zuverlässigere Software
12.2 Reale Auswirkung: Eine Fallstudie
Szenario: Ein Startup mit 20 Entwicklern.
Ohne automatisierte Qualitätschecks:
- 30 Minuten pro Code-Review (hauptsächlich Style-Probleme)
- 50 Pull Requests pro Woche
- 25 Stunden/Woche für manuelle Review
- 5 Bugs pro Woche erreichen Produktion (2 Stunden jeweils zum Beheben)
- Gesamtkosten: 35 Stunden/Woche = 175.000€/Jahr
Mit automatisierten Qualitätschecks:
- 10 Minuten pro Code-Review (nur Logik und Design)
- 50 Pull Requests pro Woche
- 8,3 Stunden/Woche für menschliche Review
- 1 Bug pro Woche erreicht Produktion (2 Stunden zum Beheben)
- Gesamtkosten: 10,3 Stunden/Woche = 51.500€/Jahr
Ersparnis: 123.500€ pro Jahr
Plus immaterielle Vorteile:
- Zufriedenere Entwickler (weniger langweilige Arbeit)
- Schnellere Feature-Lieferung
- Höhere Produktqualität
- Bessere Teammoral
13. Teil 10: Häufige Fallstricke und wie man sie vermeidet
13.1 Fallstrick 1: “Ich füge Qualitätschecks später hinzu”
Das Problem: Qualitätschecks zu einer bestehenden Codebasis mit Tausenden Verstößen hinzuzufügen ist überwältigend.
Die Lösung: Beginnen Sie mit Qualitätschecks vom ersten Tag an. Machen Sie den ersten Commit zu:
- Projektstruktur
pyproject.tomlmit Ruff-Konfiguration- GitHub Actions Workflow für Qualitätschecks
13.2 Fallstrick 2: “Mein Code funktioniert, warum ist Style wichtig?”
Das Problem: Fokus nur auf Funktionalität, Wartbarkeit ignorieren.
Die Lösung: Denken Sie daran: Code wird 10x mehr gelesen als geschrieben. Qualität ist eine Investition in zukünftige Produktivität.
13.3 Fallstrick 3: “Auto-Formatter machen meinen Code hässlich”
Das Problem: Persönliche Style-Präferenzen kollidieren mit automatisierten Formattern.
Die Lösung: Vertrauen Sie dem Formatter. Konsistenz im Team ist wertvoller als individuelle Präferenz.
13.4 Fallstrick 4: “Type Hints sind zu viel Arbeit”
Das Problem: Type Hints vermeiden, weil sie zusätzliche Zeit zum Schreiben brauchen.
Die Lösung: Type Hints sparen weit mehr Zeit als sie kosten, indem sie Bugs früh fangen. Beginnen Sie mit Funktionssignaturen.
13.5 Fallstrick 5: “CI/CD-Checks verlangsamen uns”
Das Problem: Fehlgeschlagene Checks als Blocker statt als Helfer sehen.
Die Lösung: Führen Sie Checks lokal vor dem Pushen aus. Verwenden Sie Pre-commit-Hooks. CI wird ein Sicherheitsnetz, kein Flaschenhals.
14. Teil 11: Tools-Vergleich und Ökosystem
14.1 Die Python-Qualitäts-Tools-Landschaft
14.2 Linters: Ruff vs. Flake8 vs. Pylint
Geschwindigkeit
- Ruff: 10-100x schneller (Rust-basiert)
- Flake8: Moderate Geschwindigkeit (Python)
- Pylint: Am langsamsten (am gründlichsten)
- Gewinner: Ruff - Geschwindigkeit ermöglicht häufiges Prüfen
Regeln
- Ruff: 800+ Regeln (umfassend)
- Flake8: 200+ Regeln (erweiterbar mit Plugins)
- Pylint: 300+ Regeln (opinionated)
- Gewinner: Ruff - Am umfassendsten out of the box
Konfiguration
- Ruff: Einfach, funktioniert mit pyproject.toml
- Flake8: Verwendet .flake8 oder setup.cfg
- Pylint: Komplexe .pylintrc
- Gewinner: Ruff - Moderne Konfiguration
Auto-Fix
- Ruff: Umfangreiche Auto-Fix-Unterstützung
- Flake8: Begrenzt (über Plugins)
- Pylint: Minimales Auto-Fix
- Gewinner: Ruff - Beste Auto-Fix-Fähigkeiten
Empfehlung: Verwenden Sie Ruff für neue Projekte. Erwägen Sie Flake8 nur, wenn Sie spezifische Plugins benötigen, die in Ruff noch nicht verfügbar sind.
14.3 Formatter: Ruff Format vs. Black
Geschwindigkeit
- Ruff Format: 10-100x schneller (Rust)
- Black: Standardgeschwindigkeit (Python)
- Gewinner: Ruff Format - Signifikant schneller
Style
- Ruff Format: Kompatibel mit Black
- Black: Der ursprüngliche opinionated Style
- Gewinner: Unentschieden - Nahezu identische Ausgabe
Konfiguration
- Ruff Format: Teil der vereinheitlichten Ruff-Konfiguration
- Black: Separate Konfiguration
- Gewinner: Ruff Format - Ein Tool, eine Konfiguration
Stabilität
- Ruff Format: Neuer (2023+), schnell stabilisierend
- Black: Ausgereift (2018+), kampferprobt
- Gewinner: Black für ultra-konservative Projekte, Ruff Format für moderne Entwicklung
Empfehlung: Verwenden Sie Ruff Format für vereinheitlichtes Tooling. Bleiben Sie nur bei Black, wenn Sie spezifische Kompatibilitätsanforderungen haben.
14.4 Type Checker: Pyright vs. mypy
Geschwindigkeit
- Pyright: 5-10x schneller (TypeScript/Node.js)
- mypy: Standardgeschwindigkeit (Python)
- Gewinner: Pyright - Viel schneller bei großen Codebasen
IDE-Integration
- Pyright: In VS Code Pylance eingebaut
- mypy: Benötigt separate Extension
- Gewinner: Pyright - Nahtlose VS Code-Erfahrung
Type Inference
- Pyright: Intelligentere Inferenz
- mypy: Gute Inferenz, weniger ausgeklügelt
- Gewinner: Pyright - Besser beim Ableiten komplexer Typen
Reife
- Pyright: Neuer (2019+), Microsoft-unterstützt
- mypy: Älter (2012+), weit verbreitet
- Gewinner: mypy für Legacy-Projekte, Pyright für neue Projekte
Empfehlung: Verwenden Sie Pyright, wenn Sie VS Code verwenden. Verwenden Sie mypy, wenn Sie bestehende mypy-Konfiguration haben oder spezifische Plugins benötigen.
15. Zusammenfassung: Wichtige Erkenntnisse
15.1 Funktionierender Code ≠ Qualitätscode
Code, der läuft, ist erst der Anfang. Professionelle Software muss sein:
- Lesbar - Einfach für Menschen zu verstehen
- Wartbar - Einfach zu modifizieren und zu erweitern
- Konsistent - Folgt Team- und Community-Standards
- Typsicher - Fängt Fehler vor der Laufzeit
15.2 Qualitätschecks automatisieren
Verlassen Sie sich nicht auf Menschen, um Style-Probleme zu fangen:
- Verwenden Sie Ruff für Linting und Formatierung
- Verwenden Sie Pyright für Type Checking
- Führen Sie Checks in CI/CD aus (GitHub Actions)
- Verwenden Sie Pre-commit-Hooks, um Probleme früh zu fangen
15.3 Folgen Sie PEP 8
Pythons Style Guide ist nicht optional:
- Lernen Sie die Schlüsselregeln (Abstände, Benennung, Zeilenlänge)
- Verwenden Sie Tools, die PEP 8 automatisch durchsetzen
- Vertrauen Sie dem Formatter, um Style konsistent zu machen
15.4 Type Hints sind Ihr Freund
Type Hints fangen Bugs, bevor sie die Produktion erreichen:
- Beginnen Sie mit Funktionssignaturen
- Verwenden Sie
|für Union-Typen (z.B.str | None) - Lassen Sie Pyright Typ-Nichtübereinstimmungen fangen
- Ihr zukünftiges Ich wird Ihnen danken
15.5 Qualität einbauen, nicht nachträglich anbringen
Qualität ist keine Phase—es ist eine Praxis:
- Konfigurieren Sie Qualitäts-Tools am ersten Tag
- Führen Sie Checks vor dem Committen aus
- Machen Sie das Bestehen von Checks zur Voraussetzung für das Mergen
- Verbessern Sie Ihre Standards kontinuierlich
15.6 Der ROI ist real
Automatisierte Qualitätschecks sparen Zeit und Geld:
- Schnellere Code-Reviews
- Weniger Bugs in Produktion
- Einfacheres Onboarding für neue Entwickler
- Höhere Team-Produktivität
16. Praktische Aufgabe
16.1 Aufgabe: Road Profile Viewer reparieren
- Repository klonen:
git clone https://github.com/your-username/road-profile-viewer.git cd road-profile-viewer - Umgebung einrichten:
uv sync --dev - Qualitätschecks ausführen:
uv run ruff check . uv run ruff format --check . uv run pyright - Alle Probleme beheben:
- Ungenutzte Imports entfernen
- Abstandsverstöße beheben
- Namenskonventionen korrigieren
- Toten Code entfernen
- Type Hints zu allen Funktionen hinzufügen
- Fixes verifizieren:
uv run ruff check . # Sollte 0 Fehler zeigen uv run ruff format --check . # Sollte alle Dateien OK zeigen uv run pyright # Sollte 0 Fehler zeigen - Committen und pushen:
git add . git commit -m "Fix code quality issues" git push origin main - GitHub Actions verifizieren: Prüfen Sie, dass alle CI/CD-Checks auf GitHub bestehen.
17. Zusätzliche Ressourcen
17.1 Offizielle Dokumentation
- PEP 8: python.org/dev/peps/pep-0008
- Ruff: docs.astral.sh/ruff
- Pyright: microsoft.github.io/pyright
- Python Type Hints: docs.python.org/3/library/typing.html
17.2 Lernressourcen
- Real Python - Code-Qualität: realpython.com/python-code-quality
- Effective Python: Buch von Brett Slatkin
- Clean Code in Python: Buch von Mariano Anaya
17.3 Tools und Extensions
- VS Code Ruff Extension: Suchen Sie “Ruff” im VS Code Marketplace
- VS Code Pylance: Enthält Pyright (standardmäßig mit Python-Extension installiert)
- pre-commit: pre-commit.com
19. Referenzen
[1] PEP 8 - Style Guide for Python Code. https://www.python.org/dev/peps/pep-0008/
[2] Ruff Official Documentation. https://docs.astral.sh/ruff/
[3] Astral - Modern Python Tooling. https://astral.sh/
[4] Pyright Documentation. https://microsoft.github.io/pyright/
[5] Black - The Uncompromising Code Formatter. https://black.readthedocs.io/
[6] Flake8 Documentation. https://flake8.pycqa.org/
[7] mypy - Optional Static Typing for Python. https://mypy-lang.org/
[8] Python Type Hints - Official Documentation. https://docs.python.org/3/library/typing.html
[9] Real Python - Python Code Quality Tutorial. https://realpython.com/python-code-quality/
[10] Martin, Robert C. “Clean Code: A Handbook of Agile Software Craftsmanship.” Prentice Hall, 2008.
[11] Slatkin, Brett. “Effective Python: 90 Specific Ways to Write Better Python.” Addison-Wesley, 2019.
[12] Anaya, Mariano. “Clean Code in Python: Develop Maintainable and Efficient Code.” Packt Publishing, 2021.
[13] GitHub Actions Documentation. https://docs.github.com/en/actions
[14] pre-commit Framework. https://pre-commit.com/
[15] NumPy Type Hints Documentation. https://numpy.org/doc/stable/reference/typing.html
Hinweis: Diese Vorlesung basiert auf Python 3.12+ und dem Tooling, das ab Oktober 2025 verfügbar ist. Tool-Versionen und spezifische Features können sich im Laufe der Zeit weiterentwickeln.