12 KiB
Executable File
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. mittyping) – 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:
isortundblackkö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.tomloderrequirements.txtfest 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
--checkin 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.