Files
it-know-how/python/black.md
T
2026-03-27 12:58:01 +01:00

12 KiB
Executable File
Raw Blame History

Hier eine umfassende, aber für Einsteiger verständliche Einführung in black, den „opinionated“ Python-Code-Formatter.


1. Grundidee von black

Was ist black?

  • black ist ein automatisches Formatierungs-Tool für Python.
  • Es ändert nur die Formatierung, nicht die Logik deines Codes.
  • Es ist „opinionated“: Es gibt nur sehr wenige Einstellungen black entscheidet den Stil für dich.

Zentrale Idee:

You are not your code style.
Statt darüber zu diskutieren, ob ein Leerzeichen hier oder dort besser ist, überlässt du das black.

Ziel:

  • einheitlicher Stil
  • weniger Diskussionen in Code Reviews
  • Fokus auf inhaltliche Fehler, nicht auf Formatierung

2. Was macht black konkret?

Black nimmt deinen Python-Code, parst ihn und schreibt ihn nach festen Regeln neu. Beispiele:

2.1 Installation

pip install black

2.2 Einfache Nutzung

Eine einzelne Datei formatieren:

black main.py

Ein ganzes Projekt:

black .

Nur anzeigen, was geändert würde (ohne zu schreiben):

black --diff --check .

3. Praxisnahe Formatierungsbeispiele

3.1 Zeilenumbrüche und Einrückung

Vorher:

def very_long_function_name(arg1,arg2,arg3,arg4,arg5,arg6,arg7=False,arg8=None):
    return (arg1+arg2+arg3+arg4+arg5+arg6)

Nachher (black):

def very_long_function_name(
    arg1,
    arg2,
    arg3,
    arg4,
    arg5,
    arg6,
    arg7=False,
    arg8=None,
):
    return arg1 + arg2 + arg3 + arg4 + arg5 + arg6

Was passiert?

  • Argumente werden sauber untereinander geschrieben.
  • Operatoren (+) werden mit Leerzeichen versehen.
  • Abschluss-Komma nach dem letzten Argument (hilft bei späteren Änderungen).

3.2 Strings und Anführungszeichen

Black bevorzugt fast immer doppelte Anführungszeichen.

Vorher:

name = 'Alice'
message = 'Hello, ' + name + '!'

Nachher:

name = "Alice"
message = "Hello, " + name + "!"

Ausnahmen:

  • Wenn ein String doppelte Anführungszeichen enthält, kann black einzelne beibehalten, um weniger zu escapen.

3.3 Leerzeichen und Klammern

Vorher:

result=(1+2)*3
if x==42:
    print( 'Answer',x )

Nachher:

result = (1 + 2) * 3
if x == 42:
    print("Answer", x)

Black:

  • fügt Leerzeichen um Operatoren hinzu (1 + 2, x == 42),
  • entfernt unnötige Leerzeichen (print( 'Answer',x )print("Answer", x)).

3.4 Collections (Listen, Dicts, Sets)

Vorher:

config = {"host":"localhost","port":5432,"debug":True}

Nachher:

config = {
    "host": "localhost",
    "port": 5432,
    "debug": True,
}

Vorteile:

  • Bessere Lesbarkeit
  • Leicht, neue Einträge hinzuzufügen (wegen Abschluss-Komma).

3.5 Lange Ausdrücke

Vorher:

query = session.query(User).filter(User.is_active==True, User.signup_date>=start_date, User.signup_date<=end_date).order_by(User.signup_date.desc())

Nachher:

query = (
    session.query(User)
    .filter(
        User.is_active == True,
        User.signup_date >= start_date,
        User.signup_date <= end_date,
    )
    .order_by(User.signup_date.desc())
)

Black bricht lange Zeilen so um, dass:

  • sie unter der vorgegebenen Maximalbreite bleiben (standard: 88 Zeichen),
  • die Struktur des Codes klarer sichtbar wird.

4. Abgrenzung zu verwandten Tools

4.1 Formatter vs. Linter vs. Typprüfer

  • Formatter (Formatierer):
    Passen das Aussehen deines Codes an z.B. black, autopep8, yapf.
  • Linter:
    Finden mögliche Fehler, Stilprobleme oder unschöne Konstrukte z.B. flake8, pylint, ruff.
  • Typprüfer:
    Prüfen, ob Typen konsistent sind (z.B. mit typing) z.B. mypy, pyright.

Black ist nur ein Formatter.


4.2 Black vs. autopep8

autopep8:

  • Ziel: Code so anpassen, dass er PEP8-konform ist.
  • Orientierung direkt an den PEP8-Regeln.
  • Viele Optionen (z.B. bestimmte Checks an- oder abschalten).

black:

  • Ziel: konsequenter, einheitlicher Stil nicht nur PEP8, sondern zusätzliche strenge Regeln.
  • Sehr wenige Konfigurationsmöglichkeiten (bewusst!).
  • Output ist oft deutlich „strenger” und einheitlicher als autopep8.

4.3 Black vs. yapf

yapf:

  • Google-Tool zur Formatierung von Python.
  • Sehr konfigurierbar: du kannst deinen Style stark beeinflussen (ähnlich wie bei C++/clang-format).
  • Mehr Freiheit, aber dadurch auch mehr Diskussionen möglich.

black:

  • „Meine Regeln oder gar nicht“.
  • Ziel: Diskussionen vermeiden, daher kaum Konfigurationsoptionen.
  • Sehr stabiler, vorhersehbarer Output.

4.4 Black vs. isort

isort ist ein Tool, um Imports zu sortieren und zu gruppieren.

  • Sortiert import-Zeilen alphabetisch und nach Gruppen:
    • Standardbibliothek
    • Third-Party
    • Projektinterne Module

Black:

  • Formatiert auch Imports (Zeilenumbrüche, Leerzeichen),
  • sortiert sie aber nicht nach Paketnamen.

Typischerweise nutzt man:

isort .
black .

Oder beides zusammen über Tools wie ruff oder pre-commit.


5. Welche Probleme löst black?

5.1 Konsistenter Stil in Teams

Ohne Tool:

  • Jeder schreibt „sein“ Python.
  • Unterschiedliche Leerzeichen, Umbrüche, String-Stile, etc.
  • Code wirkt „bunt“ und uneinheitlich.

Mit black:

  • Jedes Commit, jede Datei, jede Funktion hat denselben Stil.
  • Neue Teammitglieder lernen schneller, was „üblich“ ist es ist einfach: das, was black macht.

5.2 Weniger Diskussionen in Code Reviews

Vor black:

  • Kommentare wie: „Bitte hier ein Leerzeichen einfügen.“
  • „Kannst du die Argumente untereinander schreiben?“
  • „Wir verwenden eigentlich doppelte Anführungszeichen.“

Mit black:

  • Reviewer sagen: „Bitte einmal black drüber laufen lassen.“
  • Fokus liegt auf:
    • Ist der Algorithmus korrekt?
    • Sind die Funktionen gut benannt?
    • Sind Tests vorhanden?

5.3 Bessere Lesbarkeit & Wartbarkeit

  • Lange Zeilen werden sinnvoll umgebrochen.
  • Verschachtelte Ausdrücke werden strukturiert.
  • Datensammlungen (Listen, Dicts) werden mehrzeilig und übersichtlich dargestellt.

Beispiel: Eine unübersichtliche Dict-Liste wird automatisch gut lesbar formatiert.

Vorher:

users=[{"id":1,"name":"Alice","active":True},{"id":2,"name":"Bob","active":False}]

Nachher:

users = [
    {"id": 1, "name": "Alice", "active": True},
    {"id": 2, "name": "Bob", "active": False},
]

5.4 Weniger „Rauschen“ in Git-Diffs

Manuell Änderungen + Formatierung:

  • Du änderst eine Zeile, formatierst etwas,
  • der Diff zeigt viele Änderungen, obwohl nur wenig Logik geändert wurde.

Mit black:

  • Wenn alle Dateien bereits formatiert sind, entstehen bei späteren Änderungen klarere Diffs:
    • Format ist überall gleich,
    • nur die wirklich geänderte Logik fällt auf.

6. Herausforderungen und typische Stolpersteine

6.1 Einstieg in ein bestehendes Projekt

Problem:

  • Du führst black in einem alten, großen Projekt ein.
  • Beim ersten Durchlauf ändert black Hunderte/tausende Dateien.
  • Git-Diff ist riesig.

Lösungen / Best Practices:

  • Einmaliger „Formatting-Commit“ (nur Style):
    • In einem eigenen Commit alle Dateien mit black formatieren.
    • Danach neue Commits nur mit funktionalen Anpassungen.
  • Oder schrittweise:
    • Nur neue/aktuell bearbeitete Module mit black formatieren.
    • z.B. mit pre-commit-Hook nur geänderte Dateien behandeln.

6.2 „Mir gefällt der Stil nicht!“

Black ist sehr strikt:

  • Du kannst nicht „mal eben“ sagen:
    • „Ich möchte lieber 120 statt 88 Zeichen pro Zeile“ (ok, das geht als Option)
    • Aber: Du kannst nicht festlegen, wie exakt bestimmte Konstrukte formatiert werden.

Beispiel: Viele stören sich zunächst an:

  • doppelten Anführungszeichen,
  • „ungewöhnlichen“ Zeilenumbrüchen.

Wichtig:

  • black ist ein Team-Tool.
  • Man einigt sich darauf, den Stil zu akzeptieren, um Diskussionen zu vermeiden.

6.3 Integration mit anderen Tools (z.B. isort, flake8, ruff)

Typische Stolperfallen:

  • isort und black können sich widersprechen, wenn sie unterschiedliche Maximalzeilenlängen nutzen.
  • Linter können sich über Formatierung beschweren, wenn sie anders konfiguriert sind als black.

Best Practice:

  • Einheitliche Konfiguration, z.B. in pyproject.toml:
[tool.black]
line-length = 88

[tool.isort]
profile = "black"
line_length = 88

So passen Formatierung und Importsortierung zusammen.


6.4 Änderungen zwischen Black-Versionen

Black entwickelt sich weiter.

  • In seltenen Fällen ändert eine neue Version den Stil leicht.
  • Dann kann ein erneuter Durchlauf große Diffs erzeugen.

Abhilfe:

  • Black-Version in pyproject.toml oder requirements.txt fest pinnen:
black==24.4.2
  • Gelegentlich bewusst aktualisieren und einmaliger Reformatting-Commit.

6.5 Performance bei sehr großen Projekten

Für normale Projekte ist black schnell genug.
Bei sehr großen Repositories kann einmaliges Formatieren aber dauern.

Lösungen:

  • Nur geänderte Dateien formatieren (z.B. über pre-commit).
  • In CI nur black --check . laufen lassen (prüft, ob alles formatiert ist, ohne neu zu schreiben).

7. Black in der Praxis: Workflows

7.1 Integration in den Editor/IDE

Die meisten Editoren können black beim Speichern ausführen:

  • VS Code:
    • Erweiterung „Python“ installieren.
    • In settings.json:
{
    "python.formatting.provider": "black",
    "editor.formatOnSave": true
}
  • PyCharm:
    • Externes Tool konfigurieren oder über Plugins.

Vorteil:

  • Du denkst nicht mehr über Formatierung nach: Speichern = fertig formatiert.

7.2 Verwendung mit pre-commit

pre-commit ist ein Tool, das Skripte ausführt, bevor ein Git-Commit akzeptiert wird.

Installieren:

pip install pre-commit

In .pre-commit-config.yaml:

repos:
  - repo: https://github.com/psf/black
    rev: 24.4.2  # Version anpassen
    hooks:
      - id: black

Aktivieren:

pre-commit install

Jetzt wird bei jedem git commit black auf die geänderten Dateien angewandt.
Das stellt sicher, dass alles im Repo immer formatiert ist.


7.3 Black in der CI-Pipeline

In CI-Systemen (GitHub Actions, GitLab CI, etc.) kannst du prüfen, ob der Code schon formatiert ist.

Beispiel (CLI):

black --check .
  • Exit-Code 0: alles ok.
  • Exit-Code ≠ 0: irgendetwas müsste formatiert werden.

Das verhindert, dass unformatierter Code in main oder master landet.


8. Zusammenfassung

  • black ist ein sehr strenger, kaum konfigurierbarer Formatter für Python-Code.
  • Ziel:
    • einheitlicher Stil,
    • keine Diskussionen über Formatierung,
    • Fokus auf Logik und Qualität statt auf Leerzeichen.
  • Abgrenzung:
    • black formatiert nur es ist kein Linter und kein Typprüfer.
    • Im Vergleich zu autopep8/yapf: weniger konfigurierbar, dafür klarer, einheitlicher Stil.
  • Es löst:
    • Stil-Inkonsistenz, Formatierungs-Diskussionen, „Rauschen“ in Diffs.
  • Herausforderungen:
    • Einstieg in ältere Projekte,
    • wenig Einfluss auf Stil,
    • Abstimmung mit anderen Tools, Versionsänderungen.
  • In der Praxis:
    • Nutze black im Editor (Format-on-save),
    • im pre-commit-Hook,
    • und als --check in der CI.

Wenn du möchtest, kann ich dir im nächsten Schritt ein kleines Beispielprojekt konstruieren (mit pyproject.toml, pre-commit, isort/black-Konfiguration), damit du siehst, wie man black von Anfang an sauber einrichtet.