What Does Black Do? Python's Code Formatter Explained

How Black formats Python code, why it's deliberately unconfigurable, and how it differs from autopep8 and yapf

Black reformats your Python source code to a single, consistent style — automatically, on every save or commit, with almost no configuration options. That last part is the point, not a limitation.

What it actually changes

Run black . on a project and it rewrites: quote style (double quotes, with narrow exceptions), line length (88 characters by default), trailing commas, whitespace around operators, indentation consistency, and how it wraps long function calls, lists, and dicts across multiple lines. It doesn’t touch logic — only formatting.

# before
def greet(name,greeting='Hello'):
    return(greeting+", "+name+"!")

# after black
def greet(name, greeting="Hello"):
    return greeting + ", " + name + "!"

Why “uncompromising” is the actual feature

Older formatters like autopep8 and yapf are configurable — you choose quote style, line length, bracket wrapping rules, and so on. That sounds like a feature until a team spends real meeting time arguing over tabs vs spaces or single vs double quotes. Black deliberately offers almost none of that. You run it, it produces one specific output, and the debate ends. The trade-off is you don’t get to have opinions about the formatting — but most teams that adopt Black report that’s exactly the relief they wanted.

Black vs autopep8 vs yapf

  • autopep8 fixes PEP 8 violations but leaves most stylistic choices (quote style, wrapping) up to you — it’s a linter-compliance tool, not a full reformatter.
  • yapf (Google’s formatter) is highly configurable, closer to clang-format’s philosophy of “configure it to match your house style.”
  • Black picks one style and applies it uniformly, with configuration limited mostly to line length and a small set of target Python versions.

If your team wants a formatter with zero bikeshedding potential, Black is the default choice today — it’s what Ruff’s formatter also targets compatibility with, if you’re already using Ruff for linting and want one less tool. For a fuller breakdown including Ruff’s format-plus-lint combination, see Black vs Ruff vs autopep8 vs yapf.

Configuring Black

There genuinely isn’t much to configure, and that’s intentional — but the handful of options that exist live in pyproject.toml under [tool.black]:

[tool.black]
line-length = 100
target-version = ["py312"]
skip-string-normalization = true

line-length overrides the 88-character default. target-version tells Black which Python syntax features it’s safe to assume when formatting. skip-string-normalization is the one escape hatch if you don’t want Black converting single quotes to double quotes — everything else about Black’s style is fixed and isn’t meant to be tuned.

Running it in practice

Most projects run Black as a pre-commit hook or a CI check (black --check . fails the build on unformatted code) rather than trusting developers to remember to run it manually. Editor integrations (format-on-save) are common enough that in a Black-adopting codebase, you often never think about formatting at all.

TopicsToolingExplainerCode Style