PCPP1 Block 2: Coding-Konventionen (PEPs, PEP 8, PEP 257, PEP 484)
Track Python · PCPP1 Block 2 (Ziele 2.1 bis 2.8) · ca. 55 Min.
Worum es geht
Block 2 ist laut Quelle der kleinste PCPP1-Block: 12 % der Prüfung, 7 Fragen (Stand der Quelle: 1. Oktober 2026, bitte vor der Buchung prüfen). Die Quelle nennt ihn “reines Auswendigwissen” und damit gut zu holen. Geprüft werden PEP 1, PEP 8, PEP 20, PEP 257 und PEP 484. Praktisch ist das Wissen auch: Es entscheidet, ob dein Python-Code für andere Entwickler wie Python aussieht oder wie übersetztes TypeScript.
Diese Lektion zeigt jede Regel an einem lauffähigen Beispiel und lässt dich in fünf Übungen Namen prüfen, Werkzeuge zuordnen, Code nach PEP 8 reparieren, einen Docstring schreiben und Type Hints ergänzen. Nicht behandelt: die Details der PEP-Prozess-Schritte (PEP 1) über die Typen und Status hinaus, und die vollständige Liste aller PEP-8-Regeln. Die Quelle nennt nur die prüfungsrelevanten.
Ablauf: Tabelle JS/TS gegen Python, acht kurze Schritte, fünf Übungen.
Von JS/TS her gedacht
In JS/TS hast du die Konventionen an Werkzeuge ausgelagert. In Python gibt es dieselben Rollen, nur andere Namen.
| Thema | JS/TS | Python |
|---|---|---|
| Stilregeln | Airbnb- oder Standard-Style, Prettier-Defaults | PEP 8 (ein offizielles Dokument) |
| Funktionen, Variablen | camelCase (computeTotal) |
snake_case (compute_total) |
| Klassen | PascalCase (ShoppingCart) |
CapWords, also dasselbe (ShoppingCart) |
| Konstanten | MAX_SIZE |
MAX_SIZE |
| “privat” | #feld oder TS-private |
ein führender Unterstrich _feld (nur Konvention) |
| Prüfer (Linter) | ESLint | pycodestyle, flake8, pylint, ruff |
| Formatierer | Prettier | black, autopep8, isort (nur Imports) |
| Typen | TypeScript, geprüft von tsc |
Type Hints, geprüft von mypy |
| Doku am Code | JSDoc-Kommentar /** ... */ |
Docstring """...""", zur Laufzeit abrufbar |
Zwei Unterschiede sind wichtig. Erstens: Ein Docstring ist kein Kommentar, sondern ein String-Objekt, das Python am Objekt speichert (__doc__). Zweitens: Type Hints sehen aus wie TypeScript, aber Python prüft sie zur Laufzeit nicht. TS-Typen verschwinden nach dem Kompilieren, Python-Hints bleiben als Daten erhalten (__annotations__) und werden trotzdem ignoriert.
Konzept in kleinen Schritten
Schritt 1: Die PEPs im Überblick (Ziel 2.1)
PEP heißt Python Enhancement Proposal: ein Dokument für neue Features, Prozesse oder Informationen. Fünf PEPs sind prüfungsrelevant:
| PEP | Titel | Worum es geht |
|---|---|---|
| 1 | PEP Purpose and Guidelines | der Prozess hinter PEPs: Zweck, Typen, Ablauf |
| 8 | Style Guide for Python Code | Stil: Layout, Namen, Leerzeichen, Empfehlungen |
| 20 | The Zen of Python | 19 Leitsätze, abrufbar mit import this |
| 257 | Docstring Conventions | wie man Docstrings schreibt |
| 484 | Type Hints | Typannotationen für Funktionen und Variablen |
Nach PEP 1 gibt es drei Typen (types) von PEPs:
- Standards Track: neue Sprachfunktionen.
- Informational: Hinweise und Richtlinien, ohne verbindlich zu sein.
- Process: Änderungen an Prozessen, zum Beispiel PEP 1 selbst.
Dazu kommt der Status eines PEP. Die Quelle nennt: Draft, Accepted, Final, Rejected, Withdrawn, Deferred, Superseded. Das ist eine Liste von Beispielen (“zum Beispiel”), ob die Prüfung weitere Status kennt, bitte prüfen.
Der Zen of Python (PEP 20) steht direkt in der Sprache. Die Quelle sagt: 19 Aphorismen, der 20. Platz ist absichtlich leer. Ausprobieren:
Fünf Sätze aus der Quelle zum Merken: “Beautiful is better than ugly”, “Explicit is better than implicit”, “Simple is better than complex”, “Readability counts”, “Errors should never pass silently”.
Schritt 2: PEP 8, Layout (Ziel 2.2)
Die Regeln, die du als Zahlen und Reihenfolgen können musst:
- Einrückung: 4 Leerzeichen pro Ebene. Leerzeichen sind den Tabs vorzuziehen, nie mischen.
- Zeilenlänge: höchstens 79 Zeichen für Code, 72 für Kommentare und Docstrings.
- Leerzeilen: zwei zwischen Funktionen und Klassen auf oberster Ebene, eine zwischen Methoden einer Klasse. Innerhalb von Funktionen sparsam, um logische Abschnitte zu trennen.
- Zeilenumbruch in Klammern: Fortsetzungszeilen richten sich an der öffnenden Klammer aus (vertikal) oder nutzen einen hängenden Einzug (nichts nach der öffnenden Klammer, Folgezeilen eingerückt).
- Umbruch bei binären Operatoren: PEP 8 empfiehlt den Umbruch vor dem Operator.
- Kodierung: Quelldateien in UTF-8, ohne Kodierungskommentar.
- Imports: jeder auf eigener Zeile, am Dateianfang nach Modul-Docstring und vor Globals. Gruppen: Standardbibliothek, Drittanbieter, eigene Module, je eine Leerzeile dazwischen. Absolute Importe vorziehen, Wildcard-Importe (
from x import *) vermeiden.
Beispiel für beide Umbruchformen und den Umbruch vor dem Operator:
Imports in der richtigen Form (nur das Muster, die Module existieren alle):
Wichtig: Die Regel “jeder Import auf eigener Zeile” betrifft import os, sys. Bei from collections import Counter, deque stehen mehrere Namen eines Moduls erlaubt auf einer Zeile (die Quelle nennt die Ausnahme nicht ausdrücklich, bitte prüfen, ob die Prüfung danach fragt).
Schritt 3: PEP 8, Leerzeichen, Kommas, Kommentare (Ziel 2.3)
- Keine Leerzeichen direkt innerhalb von Klammern (
f(x), nichtf( x )), nicht vor Komma, Semikolon oder Doppelpunkt. - Leerzeichen um Zuweisungen und Vergleiche (
x = 1,a == b), meist auch um Rechenoperatoren. - Bei Schlüsselwortargumenten und Defaults ohne Annotation keine Leerzeichen um
=(f(a=1)). Mit Annotation mit Leerzeichen (def f(a: int = 1)). - Nachgestelltes Komma: Pflicht bei Tupeln mit einem Element, nützlich in mehrzeiligen Listen und Aufrufen.
- Anführungszeichen: PEP 8 schreibt weder einfache noch doppelte vor, es soll konsistent sein. Enthält ein String Anführungszeichen, nimm die andere Sorte statt Backslashes. Docstrings: laut PEP 257 immer
""". - Kommentare: Blockkommentare beginnen mit
#(Raute, Leerzeichen), passen zum Code und sind vollständige Sätze. Inline-Kommentare stehen mindestens zwei Leerzeichen hinter dem Code, sparsam einsetzen. Widersprüchliche oder veraltete Kommentare sind schlimmer als keine.
Schritt 4: PEP 8, Namenskonventionen (Ziel 2.4)
Das ist der Teil, den die Prüfung am liebsten abfragt. Lerne die Tabelle:
| Was | Konvention | Beispiel |
|---|---|---|
| Module | kurz, Kleinbuchstaben, Unterstriche erlaubt | my_module |
| Pakete (packages) | kurz, Kleinbuchstaben, Unterstriche vermeiden | mypackage |
| Klassen | CapWords | ShoppingCart |
| Exceptions | CapWords mit Endung Error |
ConfigError |
| Funktionen und Variablen | Kleinbuchstaben mit Unterstrichen | compute_total |
| Konstanten | Großbuchstaben mit Unterstrichen | MAX_SIZE |
| Methoden, erster Parameter | self (Instanz), cls (Klassenmethode) |
def f(self) |
| intern | ein führender Unterstrich | _helper |
| Name Mangling | zwei führende Unterstriche | __secret |
| Kollision mit Schlüsselwort | ein nachgestellter Unterstrich | class_ |
| Typvariablen | kurze CapWords | T, AnyStr |
Dazu: Vermeide l, O und I als einzelne Variablennamen, weil sie wie 1 und 0 aussehen.
Name Mangling (name mangling) siehst du an einem Beispiel. Python benennt __secret innerhalb der Klasse intern um:
Schritt 5: PEP 8, Programmierempfehlungen (Ziel 2.5)
- Vergleiche mit
Noneperisundis not:if x is not None, nichtif not x is None. - Typprüfung per
isinstance(obj, K)statttype(obj) == K. - Leere Sequenzen sind falsch:
if seq:stattif len(seq):. Keine Vergleiche mitTrueoderFalseüber==. - Strings mit
"".join(liste)zusammensetzen statt mit+=in Schleifen. - Eine Funktion mit
defdefinieren, statt ein Lambda an einen Namen zu binden. - Exceptions von
Exceptionableiten, nicht vonBaseException. Kein nacktesexcept:, nur konkrete Exceptions fangen. - Ressourcen mit
withverwalten. In einer Funktion entweder überall oder nirgends einen Wert zurückgeben.
Warum is None und nicht == None? == kann von einer Klasse überschrieben werden (__eq__), is vergleicht die Identität und ist nicht überschreibbar. Und isinstance berücksichtigt Vererbung:
Gegenüberstellung aus der Quelle, einmal falsch und einmal richtig:
# falsch
import os, sys
def Compute( x ,y ):
if x == None: return y
l = [x,y]
return l
# richtig
import os
import sys
def compute(x, y):
if x is None:
return y
return [x, y]Zähle in der falschen Version nach: Mehrfach-Import, CapWords-Funktionsname, Leerzeichen in der Klammer und vor dem Komma, == None, zwei Anweisungen in einer Zeile, l als Name, fehlendes Leerzeichen nach dem Komma, fehlende Leerzeilen. Genau solche Listen fragt die Prüfung ab, und Übung 3 trainiert sie.
Schritt 6: PEP 257, Docstrings (Ziel 2.6)
- Ein Docstring ist ein String-Literal als erste Anweisung in Modul, Klasse, Funktion oder Methode. Er ist über
__doc__undhelp()abrufbar. - Immer dreifache doppelte Anführungszeichen
""". - Einzeiler (one-liner): Text und schließende Anführungszeichen in einer Zeile, Imperativ (“Return the sum.”), keine Leerzeile davor oder danach, keine Wiederholung der Signatur.
- Mehrzeiler (multi-line): Zusammenfassungszeile, dann eine Leerzeile, dann Details. Die schließenden Anführungszeichen stehen in einer eigenen Zeile.
- Klassen-Docstrings werden von einer Leerzeile gefolgt. Ein Skript-Docstring dient als Nutzungshinweis.
- Kommentar vs. Docstring: Docstrings beschreiben, was etwas tut und wie man es nutzt. Kommentare erklären Implementierungsdetails.
Der Docstring ist zur Laufzeit da, ein Kommentar nicht. Ein String an der zweiten Stelle ist kein Docstring mehr:
Die Quelle zeigt Docstrings auf Englisch. Für die Prüfung ist das üblich. Für deine eigenen Projekte gilt, was das Team vereinbart.
Schritt 7: PEP 484, Type Hints (Ziel 2.7)
- Annotationen:
def f(x: int) -> str:undname: str = "Ada". - Python prüft sie zur Laufzeit nicht. Sie dienen Werkzeugen (zum Beispiel
mypy) und Lesern. Zugriff überf.__annotations__. - Modul
typing:Optional[int](kannNonesein),Union[int, str],Any,Callable,List[int]. Ab Python 3.9 funktionierenlist[int], ab 3.10int | None.
Das ist der größte Unterschied zu TypeScript: Dort bricht tsc den Build ab, in Python passiert beim Ausführen nichts. Den Fehler findet nur mypy, wenn du es laufen lässt.
Merke: Optional[int] ist dasselbe wie int | None (ab 3.10) und bedeutet “int oder None”, nicht “Argument darf fehlen”.
Schritt 8: Werkzeuge (Ziel 2.8)
Die Quelle teilt in drei Gruppen:
- Prüfer (linter):
pycodestyle(früherpep8),flake8,pylint,ruff. Sie melden Verstöße. - Automatische Korrektur und Formatierer (formatter):
autopep8,black,isort(sortiert Imports). Sie ändern den Code. - Typprüfer (type checker):
mypy.
Faustregel: Prüfer sagen dir, was nicht passt. Formatierer ändern die Datei. Der Typprüfer liest die Type Hints, ohne den Code auszuführen (statische Analyse). Welches Werkzeug genau welche Regel prüft, steht nicht in der Quelle, bitte nicht über die Gruppen hinaus raten.
Falle: die Prüfungs- und Praxisklassiker
- Zahlen verwechseln: 79 Zeichen für Code, 72 für Kommentare und Docstrings. 4 Leerzeichen. Zwei Leerzeilen auf oberster Ebene, eine zwischen Methoden.
=bei Defaults: ohne Annotationf(a=1), mit Annotationf(a: int = 1).- Paket oder Modul: Pakete möglichst ohne Unterstriche (
mypackage), Module dürfen sie haben (my_module). - Exception-Name: CapWords mit
Erroram Ende. - Docstring ist kein Kommentar: erste Anweisung,
""", über__doc__abrufbar. Einzeiler im Imperativ. - Type Hints erzwingen nichts: Der Aufruf mit falschem Typ läuft einfach. Nur
mypyund Co. melden es. - Gruppen der Werkzeuge:
isortist ein Formatierer für Imports, kein Typprüfer.ruffsteht bei den Prüfern.
Übungen
Übung 1: Namen nach PEP 8 prüfen
Jeder Eintrag nennt die Rolle und den Namen. Trage in verstoesse die Namen ein, die gegen die Namenskonvention von PEP 8 verstoßen. Schreibe nur die Namen als Strings in die Liste.
Gehe die Rollen einzeln durch und frage dich bei jedem Namen, welche Schreibweise diese Rolle verlangt. Achte auch auf Namen, die formal in Ordnung aussehen, aber einen eigenen Grund haben, vermieden zu werden.
verstoesse = ["shopping_cart", "ConfigFehler", "computeTotal", "max_size",
"my_package", "MyModule", "userName", "l"]
verstoesseÜbung 2: Werkzeuge zuordnen
Ordne jedem Szenario die Gruppe zu, zu der das passende Werkzeug gehört. Erlaubte Werte: "Pruefer", "Formatierer", "Typpruefer" oder "keines" (wenn das nicht Aufgabe eines dieser Werkzeuge ist, sondern von Python selbst oder gar nicht passiert).
- Ein Werkzeug soll melden, dass in
app.pyeine Zeile 95 Zeichen lang ist, und dabei nichts an der Datei ändern. - Die Importe aller Dateien sollen automatisch sortiert und in Gruppen gesetzt werden.
- Die CI soll fehlschlagen, wenn irgendwo
rechne(x: int)mit einemstraufgerufen wird, ohne dass der Code läuft. - Alle Dateien sollen ohne Diskussion einheitlich umformatiert werden.
- Python selbst soll beim Aufruf
rechne("a")einen Fehler auslösen, weilrechnemitx: intannotiert ist.
Frage bei jedem Szenario: Wird nur gemeldet oder wird die Datei geändert? Wird dafür der Code ausgeführt oder nur gelesen? Und bei Szenario 5: Probiere es in einer Zelle mit einer eigenen kleinen Funktion aus.
antwort = {1: "Pruefer", 2: "Formatierer", 3: "Typpruefer", 4: "Formatierer", 5: "keines"}
antwortÜbung 3: Code nach PEP 8 reparieren
Der folgende Code läuft, verstößt aber an mindestens acht Stellen gegen PEP 8 (Layout, Leerzeichen, Namen, Empfehlungen, Zeilenlänge). Repariere ihn, ohne sein Verhalten zu ändern. Die Funktion muss berechne_preis heißen, die Parameter netto und steuer behalten, und os und sys bleiben importiert.
Arbeite dich Zeile für Zeile von oben nach unten durch und halte die Gegenüberstellung aus Schritt 5 daneben. Prüfe auch das, was dort nicht vorkommt: die Einrückung innerhalb der Funktion und die Länge der Kommentarzeile (wie viele Zeichen sind dort erlaubt?).
import os
import sys
def berechne_preis(netto, steuer=0.19):
# Berechnet den Bruttopreis aus Nettopreis und Steuersatz,
# gerundet auf zwei Stellen.
if netto is None:
return 0
werte = [netto, steuer]
return round(werte[0] * (1 + werte[1]), 2)
berechne_preis(100)Übung 4: Einen Docstring nach PEP 257 schreiben
Ersetze die Zeile ______ durch einen mehrzeiligen Docstring nach PEP 257. Die Funktion bleibt unverändert. Der Docstring ist auf Englisch (wie in der Quelle) und soll eine Zusammenfassungszeile (ein ganzer Satz mit Punkt am Ende), eine Leerzeile und mindestens eine Detailzeile enthalten.
Denke an die Form: Welche Anführungszeichen, wo steht die Zusammenfassung, wie endet sie, was steht danach, wo stehen die schließenden Anführungszeichen? Achte auch auf die Zeilenlänge im Docstring und darauf, ob die Zusammenfassung eher einen Befehl oder eine Beschreibung formuliert.
def mittelwert(zahlen):
"""Return the arithmetic mean of a list of numbers.
The list must not be empty, otherwise ValueError is raised.
"""
if not zahlen:
raise ValueError("leere Liste")
return sum(zahlen) / len(zahlen)
mittelwert.__doc__Übung 5: Type Hints ergänzen
Ergänze Type Hints nach PEP 484, ohne das Verhalten zu ändern:
MAX_VERSUCHEist einint.begruessenimmt einenstrund einenint(Default bleibt1) und liefert einenstr.findenimmt eine Liste vonintund einenintund liefert den Index oderNone.
Achte bei dem Parameter mit Default auf die Schreibweise nach PEP 8.
Für eine Variable steht die Annotation hinter dem Namen und vor dem Wert. Bei Funktionen gehört die Rückgabe hinter ->. Überlege bei finde, welche zwei Möglichkeiten der Rückgabewert hat, und wie PEP 8 das = bei einem annotierten Default setzt.
MAX_VERSUCHE: int = 3
def begruesse(name: str, anzahl: int = 1) -> str:
return ("Hallo " + name + "! ") * anzahl
def finde(zahlen: list[int], ziel: int) -> int | None:
for i, z in enumerate(zahlen):
if z == ziel:
return i
return None
finde.__annotations__Merksatz und Prüfstein
Merksatz: PEP 8 sagt, wie Code aussieht (79 Zeichen, 4 Leerzeichen, snake_case, CapWords, is None), PEP 257 sagt, wie Docstrings aussehen (""", Imperativ, erste Anweisung), PEP 484 beschreibt Type Hints, die Python nie erzwingt, und Prüfer, Formatierer und Typprüfer sind drei verschiedene Werkzeuggruppen.
Prüfstein (offene Frage): Ein Kollege schreibt def get_user(id: int = None) -> User: und sagt, mypy sei dafür da, dass das Programm nie mit None abstürzt. Nenne zwei Dinge, die an dem Satz oder an der Signatur nicht stimmen, und sage, welche Werkzeuggruppe was davon findet.
Quelle: quellen/python-glossar-pcap-pcpp1.md, PCPP1 Block 2, Abschnitte 2.1 (Die PEPs im Überblick), 2.2 (Layout), 2.3 (Leerzeichen, Kommas, Anführungszeichen), 2.4 (Namenskonventionen), 2.5 (Programmierempfehlungen), 2.6 (PEP 257), 2.7 (PEP 484), 2.8 (Werkzeuge). Blockgewicht und Fragenzahl laut Quelle (Stand 1. Oktober 2026, bitte prüfen). Nicht in der Quelle, aber mit Python 3.13 ausgeführt und geprüft (bitte prüfen, ob sie in der PCPP1 gefragt werden): die Ausnahme zu mehreren Namen in from x import a, b, die Ablehnung von Strings an zweiter Stelle als Docstring, die Gleichheit von Optional[int] und int | None, der Hinweis, dass bool von int erbt, und die Vergleichsüberschreibung per __eq__. Die Entsprechungstabelle JS/TS gegen Python ist eine didaktische Zuordnung, keine Aussage der Quelle.