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), nicht f( 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 None per is und is not: if x is not None, nicht if not x is None.
  • Typprüfung per isinstance(obj, K) statt type(obj) == K.
  • Leere Sequenzen sind falsch: if seq: statt if len(seq):. Keine Vergleiche mit True oder False über ==.
  • Strings mit "".join(liste) zusammensetzen statt mit += in Schleifen.
  • Eine Funktion mit def definieren, statt ein Lambda an einen Namen zu binden.
  • Exceptions von Exception ableiten, nicht von BaseException. Kein nacktes except:, nur konkrete Exceptions fangen.
  • Ressourcen mit with verwalten. 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__ und help() 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: und name: str = "Ada".
  • Python prüft sie zur Laufzeit nicht. Sie dienen Werkzeugen (zum Beispiel mypy) und Lesern. Zugriff über f.__annotations__.
  • Modul typing: Optional[int] (kann None sein), Union[int, str], Any, Callable, List[int]. Ab Python 3.9 funktionieren list[int], ab 3.10 int | 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üher pep8), 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

  1. Zahlen verwechseln: 79 Zeichen für Code, 72 für Kommentare und Docstrings. 4 Leerzeichen. Zwei Leerzeilen auf oberster Ebene, eine zwischen Methoden.
  2. = bei Defaults: ohne Annotation f(a=1), mit Annotation f(a: int = 1).
  3. Paket oder Modul: Pakete möglichst ohne Unterstriche (mypackage), Module dürfen sie haben (my_module).
  4. Exception-Name: CapWords mit Error am Ende.
  5. Docstring ist kein Kommentar: erste Anweisung, """, über __doc__ abrufbar. Einzeiler im Imperativ.
  6. Type Hints erzwingen nichts: Der Aufruf mit falschem Typ läuft einfach. Nur mypy und Co. melden es.
  7. Gruppen der Werkzeuge: isort ist ein Formatierer für Imports, kein Typprüfer. ruff steht 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).

  1. Ein Werkzeug soll melden, dass in app.py eine Zeile 95 Zeichen lang ist, und dabei nichts an der Datei ändern.
  2. Die Importe aller Dateien sollen automatisch sortiert und in Gruppen gesetzt werden.
  3. Die CI soll fehlschlagen, wenn irgendwo rechne(x: int) mit einem str aufgerufen wird, ohne dass der Code läuft.
  4. Alle Dateien sollen ohne Diskussion einheitlich umformatiert werden.
  5. Python selbst soll beim Aufruf rechne("a") einen Fehler auslösen, weil rechne mit x: int annotiert 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_VERSUCHE ist ein int.
  • begruesse nimmt einen str und einen int (Default bleibt 1) und liefert einen str.
  • finde nimmt eine Liste von int und einen int und liefert den Index oder None.

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.