从零上手 Black:命令行动手、手动忽略标记与 pyproject.toml 配置的完整指南
发布时间:2026/9/10 9:54:09来源:尧图网络
从零上手 Black命令行动手、手动忽略标记与 pyproject.toml 配置的完整指南【免费下载链接】blackThe uncompromising Python code formatter项目地址: https://gitcode.com/GitHub_Trending/bl/blackBlack当前仓库 GitHub_Trending/bl/black自称 The uncompromising Python code formatter。当你在团队中引入它时最先需要掌握的不是某条特定风格规则而是三件事如何调用它、如何在不得不保留手工排版时明确别动这段代码、以及如何通过pyproject.toml把团队约定固化下来。本文以 docs/usage_and_configuration/the_basics.md 为骨架结合仓库中的 CLI 定义、常量与缓存实现等源码系统讲解 Black 的使用与配置全貌。读完你就能在命令行安全地格式化、接入 CI 的--check/--diff检查并为项目落地一套可复制的[tool.black]配置。Black 的工具哲学一个守规矩的 Unix 命令行程序在进入任何参数之前先理解 Black 作为命令行工具的设计底线。它被刻意设计为一个行为可预期、擅长被其他程序编辑器、pre-commit、CI调用的 Unix 风格工具没有可格式化的源码就什么都不做不会因为空目录或无匹配文件而报错退出用-作为文件名时从标准输入读取、向标准输出写入方便管道集成只在标准错误stderr上向用户输出信息从而保证 stdout 干净可以被安全地重定向或捕获除非发生内部错误、或某个 CLI 选项如--check主动要求否则以退出码 0 结束。这套行为约定贯穿下文所有选项的设计例如--check用退出码充当 CI 判断依据、--diff把 diff 打到 stdout 便于捕获都是同一设计哲学的体现。立即开始使用两种等价调用方式Black 会就地in place重排整个文件。以最省心的默认配置直接起步black {source_file_or_directory}其中参数既可以是单个文件也可以是目录传目录时 Black 会递归收集其中符合规则的文件收集与发现规则的细节见 File collection and discovery。如果以脚本方式运行不生效例如没有安装black可执行入口可以退而求其次把它当作 Python 模块来运行效果完全等价python -m black {source_file_or_directory}需要注意运行时对 Python 解释器版本有硬性要求源码入口 src/black/init.py 中有一句assert sys.version_info (3, 10), Black requires Python 3.10因此请确保运行环境是 Python 3.10 及以上。手动忽略# fmt: skip与# fmt: off/onBlack 通常不让任何代码漏网但它也承认有些排版需要手工保留对齐的字典、精心排布的表格数据等因此提供了两类逃生舱注释单行忽略行尾加上# fmt: skip该行将不被重排块级忽略以# fmt: off开始、以# fmt: on结束的代码块整体保持原样。# fmt: skip可以与其他 pragma 混合使用两种写法都合法x call(a, b) # fmt: skip # pylint # noqa y call(a, b) # fmt: skip; pylint; noqa# fmt: on/# fmt: off必须处于相同的缩进层级、且位于同一个代码块内——也就是说二者之间不允许出现超出初始缩进级别的取消缩进unindent。换言之开关要成对出现在同一嵌套层级里。作为对跨工具代码的友好表示Black 还识别 YAPF 定义了三个标记集合FMT_OFF: Final {# fmt: off, # fmt:off, # yapf: disable} FMT_SKIP: Final {# fmt: skip, # fmt:skip} FMT_ON: Final {# fmt: on, # fmt:on, # yapf: enable}可以看到# fmt:off无空格与# yapf: disable/# yapf: enable同样被接受兼容面比文档示例更广。所有这类标记注释都在词法分析阶段被专门识别并转换为不可变节点从而在换行、缩进等重排流程中被整体跳过。命令行选项逐一详解运行black --help可以查看全部选项本节将其逐一展开。选项背后的 Click 注册定义集中在 src/black/init.py 的click.option装饰器链上与下述文档一一对应。需要先记住两条总原则虽然 Black 的可调旋钮knobs这些年越来越多但它依然坚持固执己见风格类选项被刻意限制且极少新增下面列出的几乎每个命令行选项都可以用pyproject.toml文件配置详见后文 配置文件章节。-h,--help显示所有可用命令行选项并退出。-c,--code把以字符串形式传入的代码格式化后输出到 stdout。典型的快速验证场景$ black --code print ( hello, world ) print(hello, world)注意它不能与位置参数SRC同时出现——源码 src/black/init.py 中若检测到src and code is not None会直接打印用法并退出。-l,--line-length每行允许的字符数默认 88。这一默认值定义在常量模块 src/black/const.pyDEFAULT_LINE_LENGTH 88并作为 Click 参数的default传入。88 的由来、以及行长超出后的换行策略见 the_black_code_style/current_style.md 的 Line length 一节。-t,--target-version声明输出需要支持的 Python 版本。运行black --help查看--target-version即可看到完整版本清单。实践准则是列出你的代码实际支持的所有版本。例如你的代码支持 Python 3.11 到 3.13就写$ black -t py311 -t py312 -t py313在配置文件中则写成 TOML 数组target-version [py311, py312, py313]默认推断逻辑如果不显式给出Black 会先从pyproject.toml的项目元数据具体是[project.requires-python]字段推断目标版本若无法得出确定结论则回退到按文件逐个自动检测根据源码语法特征判断其所需的 Python 版本。这一帮助文本直接体现在 CLI 选项的help中见 src/black/init.py。底层作用Black 用它决定用哪套语法grammar解析你的代码有时也据此决定风格。例如函数调用中*args之后是否可加尾随逗号是 Python 3.5 才引入的语法于是 Black 只在目标版本全部 ≥ 3.5 时才补这个逗号。源码中的版本枚举见 src/black/mode.py 的TargetVersionPY33–PY315与语法能力对应的是同一文件里的Feature枚举。下面的对照示例直观展示了这一点配合短行长强制换行$ black --line-length10 --target-versionpy35 -c f(a, *args) f( a, *args, ) $ black --line-length10 --target-versionpy34 -c f(a, *args) f( a, *args ) $ black --line-length10 --target-versionpy34 --target-versionpy35 -c f(a, *args) f( a, *args )注意第三个例子只要目标版本并集里包含任一较低版本py34就不会输出仅在 3.5 才合法的尾随逗号——这正是包含所有你支持的版本这一建议的原因。--pyi无论文件扩展名是什么都把输入当**类型桩typing stub**处理。在把源码从标准输入导入时尤其有用。--ipynb无论扩展名是什么都把输入当Jupyter Notebook处理。同样在管道输入场景很有用。--python-cell-magics处理 Notebook 时把给定的 magic 加入已知的 Python magic 列表用于正确格式化带有自定义 Python magic 的 cell。默认内置的 magic 集合会显示在该选项的 help 中src/black/init.py 中PYTHON_CELL_MAGICS的排序列表。详细用法参见 使用 Black 与 Jupyter Notebook。-x,--skip-source-first-line跳过源码的第一行适合处理首行是 shebang#!/usr/bin/env python或编码声明# -*- coding: ... -*-且你不想让 Black 触碰它的场景。-S,--skip-string-normalization默认情况下 Black 把所有字符串统一为双引号并规范化字符串前缀规则见 字符串风格说明。加上此选项后字符串保持原样、不做任何改写。-C,--skip-magic-trailing-comma默认情况下 Black 把已有的尾随逗号当作这些短行应当保持拆开的信号详见 magic trailing comma 风格说明。加上此选项后这个魔法尾随逗号将被忽略、不再影响拆分决策。--preview开启有潜在破坏性、预计在下一个大版本进入稳定风格的格式改动。适合想提前体验明年风格的用户。详见 future_style.md 的 Preview style 一节。注意该 flag 产出的代码风格跨版本不做任何保证。--unstable开启--preview的全部改动外加一些最终想做、但当前已知存在问题、需要先修好才能回到--preview的实验改动。适合想参与试验并帮助反馈问题的用户。源码实现中--unstable隐含--preview见 src/black/init.py 的帮助文本 Implies --preview。同样该 flag 产出的代码风格跨版本不做任何保证。--enable-unstable-feature从--unstable风格中单独启用某个特性。可用特性清单见 future_style.md 的 unstable features 说明。该 flag只能在开启--preview时使用——源码 src/black/init.py 会校验若未启用 preview 则打印用法并退出。使用场景你正在用--preview风格而某个影响你代码的特性已从 preview 移入 unstable你希望避免因该变动反复横跳thrash于是单点启用它。这些特性的行为、甚至是否存在跨版本都不做保证。--check不回写文件只返回状态码退出码0没有任何文件需要改动退出码1有文件将被重排退出码123发生内部错误。若与--quiet组合则除了内部错误之外只返回退出码、不再输出。这一约定写在 CLI 帮助文本中src/black/init.py也是 CI 与 pre-commit 判断格式是否合格的标准接口。实测效果$ black test.py --check All done! ✨ ✨ 1 file would be left unchanged. $ echo $? 0 $ black test.py --check would reformat test.py Oh no! 1 file would be reformatted. $ echo $? 1 $ black test.py --check error: cannot format test.py: INTERNAL ERROR: Black produced code that is not equivalent to the source. Please report a bug. Oh no! 1 file would fail to reformat. $ echo $? 123--diff不回写文件只输出改动 diff。diff 打印到 stdout因此捕获起来很简单例如重定向到文件。配合--color可输出彩色 diff。$ black test.py --diff --- test.py 2021-03-08 22:23:40.84895400:00 test.py 2021-03-08 22:23:47.12631900:00 -1 1 -print ( hello, world ) print(hello, world) would reformat test.py All done! ✨ ✨ 1 file would be reformatted.--no-cache本次运行既不读取也不更新Black 的用户级缓存。Black 默认按文件维护上次格式化后是否改动过的缓存来加速重复运行--no-cache会强制对所有文件做全新分析。用途包括复现一次干净运行的格式化结果、排查缓存相关异常、或在 CI 中确保每次都是全新格式化分析。CLI 帮助文本见 src/black/init.py。--color/--no-color显示或不显示彩色 diff。仅在给出--diff时生效。--line-ranges指定后Black 会尽量只格式化这些行。要点可多次指定多个范围的并集会被格式化每个范围写作两个整数、中间用-连接START-END行号从 1 开始、两端都包含例black --line-ranges1-10 --line-ranges21-30 test.py会格式化第 1–10 行与第 21–30 行出于多行语句整体性的需要Black可能仍会格式化范围之外的行该选项不支持一次格式化多个文件或任何 Jupyter Notebook该选项不能写进pyproject.toml配置它的主要服务对象是编辑器集成例如Format Selection。已知注意事项对应上游 issue #4052当请求行附近紧邻着内容恰好与格式化结果相同的未格式化行时--line-ranges可能格式化范围外的多余行同时它会关闭--safe模式下的格式稳定性检查。--fast/--safe默认情况下 Black 在格式化后会做一次AST 安全检查本质上是把格式化前后两棵 AST 做等价性比对从机制上防止产出改变了代码语义的结果。--fast关闭该检查--safe显式开启默认即 safe。对 AST 前后差异的解释见 current_style.md 的 AST before and after formatting 一节。--required-version要求正在运行的 Black 必须是指定版本。因为不同版本格式化结果可能略有差异用它可确保项目所有贡献者使用一致版本该选项也能放进配置文件让各环境结果统一。$ black --version black, 26.5.1 (compiled: yes) $ black --required-version 26.5.1 -c format this format this $ black --required-version 31.5b2 -c still beta?! Oh no! The required version does not match the running version!也支持只传主版本号$ black --required-version 22 -c format this format this $ black --required-version 31 -c still beta?! Oh no! The required version does not match the running version!由于 稳定性政策同一年内的非预发布版本在相同选项下格式化结果不变因此只锁主版本既能保证格式稳定又不妨碍你享受不涉及格式的改进。--exclude一个正则表达式用于在递归搜索时排除匹配的文件与目录。要点空值表示不排除任何路径所有平台包括 Windows的目录分隔都写正斜杠/默认情况下 Black 也会忽略.gitignore中列出的所有路径修改该值会覆盖全部默认排除规则。默认排除项[.direnv, .eggs, .git, .hg, .ipynb_checkpoints, .mypy_cache, .nox, .pytest_cache, .ruff_cache, .tox, .svn, .venv, .vscode, __pypackages__, _build, buck-out, build, dist, venv]这些默认值在 src/black/const.py 中以DEFAULT_EXCLUDES常量的形式固化。如果正则里包含换行它会被当作verbose 正则Pythonre.VERBOSE处理——这通常用于在pyproject.toml中书写跨行规则见下文 配置格式。--extend-exclude与--exclude类似但在默认值之上追加排除项而不是覆盖它们。日常项目最常用因为它不会误伤默认排除集。--force-exclude与--exclude类似但匹配该正则的文件/目录即使被显式作为参数传入也会被排除。典型场景是以编程方式对变更文件调用 Black 的 pre-commit 钩子或编辑器插件即使钩子显式把某个文件传进来只要它命中--force-exclude就不会被格式化。--stdin-filename当源码来自 stdin 时告诉 Black 这份输入名义上属于哪个文件。它保证那些依赖 stdin 的编辑器在格式化前依然会尊重--force-exclude以及根目录探测等按文件路径进行的逻辑。--include正则表达式用于递归搜索时包含匹配的文件/目录。要点空值表示无论名称如何都包含所有文件目录分隔同样全平台使用正斜杠它会覆盖所有排除规则包括.gitignore与命令行上的排除项。默认包含项[.pyi, .ipynb]默认值对应 src/black/const.py 的DEFAULT_INCLUDES r(\.pyi?|\.ipynb)$。-W,--workers格式化多个文件时Black 可能启用进程池来加速此选项控制并行 worker 数量。也可以通过环境变量BLACK_NUM_WORKERS指定默认取系统 CPU 数量。并发取值逻辑见 src/black/concurrency.py若命令行未指定则读取BLACK_NUM_WORKERS非法值会报错提示参数来源。-q,--quiet停止输出所有非关键信息。错误消息仍会输出可用2/dev/null一并屏蔽$ black src/ -q error: cannot parse: src/black_primer/cli.py:5:6 mport asyncio ^ ParseError: bad input-v,--verbose输出未改动的文件和因排除规则被忽略的文件等信息若 Black 正在使用配置文件还会输出一条消息指明用的是哪个配置文件$ black src/ -v Using configuration from /tmp/pyproject.toml. src/blib2to3 ignored: matches the --extend-exclude regular expression src/_black_version.py wasnt modified on disk since last run. src/black/__main__.py wasnt modified on disk since last run. error: cannot parse: src/black_primer/cli.py:5:6 mport asyncio ^ ParseError: bad input reformatted src/black_primer/lib.py reformatted src/blackd/__init__.py reformatted src/black/__init__.py Oh no! 3 files reformatted, 2 files left unchanged, 1 file failed to reformat上面 wasnt modified on disk since last run 就是缓存命中的直接体现——文件自上次格式化以来未变直接跳过。--version查看所安装 Black 的版本$ black --version black, 26.5.1--config从一个配置文件读取选项。详见下文 配置文件。在 Click 中它被注册为is_eagerTrue且回调为read_pyproject_tomlsrc/black/init.py意味着它会在其他参数之前被抢先处理、立即加载配置并写入默认映射。环境变量选项Black 支持通过两个环境变量做配置BLACK_CACHE_DIR指定 Black 存储缓存文件的目录。源码 src/black/cache.py 的get_cache_dir()展示了默认行为缓存目录 BLACK_CACHE_DIR若未设置则取user_cache_dir(black)即各平台的标准用户缓存目录再追加当前 Black 版本号子目录缓存文件名形如cache.mode.pickle因此不同版本、不同模式行宽/版本/开关组合的缓存互不串扰。BLACK_NUM_WORKERS并行 worker 数。命令行选项-W/--workers优先于该环境变量见 src/black/concurrency.py 的取值顺序。三种代码输入途径除了直接传文件/目录路径Black 还支持两种非文件输入stdin → stdout用-作为路径从标准输入读取、把结果写到标准输出$ echo print ( hello, world ) | black - print(hello, world) reformatted - All done! ✨ ✨ 1 file reformatted.字符串输入用-c/--code直接传字符串。实用 Tip如果你需要 Black 把 stdin 输入当作直接通过 CLI 传入的文件对待就用--stdin-filename。这能确保那些依赖 stdin 的编辑器尊重--force-exclude规则。写回与报告模式Writeback and reporting默认行为是就地重排传入/找到的文件。有时你只想让 Black 告诉你会做什么、而不真正改写Python 文件。这种只报告模式由两个彼此独立的 flag 分别开启且可以叠加--check有文件会被重排时以退出码 1 结束详见上文--diff打印 diff 而不是重排文件。两者同时开启时Black 既不做写回、也会给出可捕获的 diff 与退出码常用于 CI/代码评审场景。输出冗长度Output verbosityBlack 整体倾向于在有用与简洁之间找到平衡。默认输出被修改的文件、错误消息外加一行简短汇总$ black src/ error: cannot parse: src/black_primer/cli.py:5:6 mport asyncio ^ ParseError: bad input reformatted src/black_primer/lib.py reformatted src/blackd/__init__.py reformatted src/black/__init__.py Oh no! 3 files reformatted, 2 files left unchanged, 1 file failed to reformat.--quiet与--verbose分别向更安静与更啰嗦两个方向调节输出量详见上文选项说明。配置文件pyproject.toml命令行好写但团队协作时更希望把约定固化进仓库。Black 可以从项目的pyproject.toml读取各命令行选项的项目级默认值——尤其适合自定义--include、--exclude/--force-exclude/--extend-exclude等模式。Pro-tip如果你在纠结我需要配置些什么吗——答案通常是不需要。Black 的全部意义就在于合理默认值。直接套用默认值你的代码就能与大量同样用 Black 格式化的项目保持一致风格。pyproject.toml是什么PEP 518 把pyproject.toml定义为存放 Python 项目构建系统要求的配置文件。借助 Poetry、Flit、Hatch 等工具它可以彻底取代setup.py与setup.cfg。Black 只是借用这一个文件、在其中认领自己的[tool.black]分区而已。Black 在哪里找这个文件默认查找逻辑是自底向上的从命令行传入的所有文件/目录的公共基目录出发找含[tool.black]分区的pyproject.toml若该目录没有就向父目录逐级查找在以下三个条件先到者处停止找到目标文件、遇到.git目录、遇到.hg目录、或到达文件系统根目录。特殊情形格式化 stdin时从当前工作目录出发查找全局配置fallback也可以在主目录固定位置放一份全局配置仅当上面按项目查找一无所获时才作为后备使用。按操作系统该配置文件应存放在注意这是 TOML 文件本身的路径而不是存放配置的目录文件名不叫pyproject.tomlWindows~\.blackUnix-likeLinux、macOS 等$XDG_CONFIG_HOME/black若未设置XDG_CONFIG_HOME环境变量则为~/.config/black这里的~指主目录Windows 上形如C:\Users\UserName对应环境变量%USERPROFILE%。--config显式指定此时 Black不再寻找任何其他配置文件运行--verbose时如果找到并使用某个文件会输出一条消息源码 src/black/init.py 会区分 user-level config、project root 的配置与--config显式指定的路径注意blackdBlack 的 HTTP 服务模式不会使用pyproject.toml配置其相关说明见 black_as_a_server。配置格式pyproject.toml是 TOML 文件内含各工具的独立分区Black 使用[tool.black]。选项键名与命令行选项的长名一致把长名去掉开头的--即可例如--line-length→line-length。上文逐个标注不能写进配置文件的选项如--line-ranges是明确例外。TOML 中的书写要点正则必须用单引号字符串等价于 Python 的 r-string避免\被 TOML 转义多行字符串会被 Black 当作 verbose 正则re.VERBOSE处理因此可以用#注释、按行组织子模式行内表示有意义的空格要用[ ]。下面是一份基础示例[tool.black] line-length 88 target-version [py37] include \.pyi?$ # extend-exclude 在默认排除之上追加排除文件或目录 extend-exclude # 以 ^/ 开头的正则只作用于项目根目录中的文件/目录 ( ^/foo.py # 排除项目根下的 foo.py | .*_pb2.py # 排除项目中任意位置的自动生成的 Protocol Buffer 文件 ) 以及一份更完整的模板[tool.black] line-length 88 target-version [py311] required-version 26 include \.pyi?$ # Formatting behavior格式化行为 skip-string-normalization false skip-magic-trailing-comma false preview false unstable false # File collection文件收集 extend-exclude ( ^/foo.py | .*_pb2.py ) force-exclude ( ^/generated/ ) 注意模板中required-version 26只锁主版本号——结合稳定性政策这既保证格式稳定又允许升级。配置查找层级Lookup hierarchy三层的优先级自下而上叠加CLI 默认值在--help中可见pyproject.toml覆盖默认值用户在命令行显式给出的选项再覆盖配置文件。还有一个容易忽略的纪律一次运行只会使用一个pyproject.toml——Black 不会查找多个文件也不会把不同目录层级上的多份配置做合并merge。因此不存在深层项目配置覆盖浅层配置的组合逻辑想要统一就得自下而上找到唯一那份。下一步把一次性命令变成日常习惯掌握上述基础后两个自然的进阶方向是配置自动发现auto-discovery让black .成为唯一需要的命令告别手工罗列文件——见 File collection and discovery与编辑器集成保存即格式化或pre-commit 源码版本控制集成提交前自动检查/修复——分别见 editors 与 source_version_control。若需在 CI 或服务化场景中运行可进一步阅读 Black 作为服务blackd 与 Black Docker 镜像。当你需要理解Black 为什么要这么排则可直接查阅 the_black_code_style 下的当前风格与预览风格文档——这也是理解--line-length、--preview等选项深层行为的最终落点。【免费下载链接】blackThe uncompromising Python code formatter项目地址: https://gitcode.com/GitHub_Trending/bl/black创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网