在现代Python开发中,代码格式的一致性对于团队协作和代码维护至关重要。本文将详细介绍两个最流行的Python代码格式化工具:Black 和 isort ,帮助你理解它们的作用、配置方法以及如何在VS Code中高效使用。
一、Black与isort是什么? 1.1 Black - 不妥协的代码格式化工具 Black 被称为”The uncompromising code formatter”(不妥协的代码格式化工具),是由Łukasz Langa开发并由Python Software Foundation维护的Python代码格式化工具。Black的核心理念是:
“Any color you like.”(任何你喜欢的颜色。)
这句话来自于Henry Ford关于Model T汽车的名言——“你可以选择任何颜色,只要它是黑色的”。Black采用了类似的哲学:通过放弃对代码格式细节的控制权,换取速度、确定性,以及从格式争论中解放出来的自由 。
Black的主要特点:
确定性输出 :相同的代码输入总是产生相同的格式化输出
最小化差异 :生成尽可能小的代码差异,使代码审查更高效
统一风格 :无论是哪个项目,使用Black格式化后的代码看起来都是一致的
AST安全检查 :格式化后会验证代码的抽象语法树(AST)是否与原始代码等效
正如SQLAlchemy的作者Mike Bayer所说:
“我想不出在我整个编程生涯中有任何单一工具能像Black这样,因为它的引入而带来如此巨大的生产力提升。”
1.2 isort - 智能的导入语句排序工具 isort (import sort的缩写)是一个Python实用工具/库,用于按字母顺序对导入语句进行排序,并自动将它们分成不同的部分和类型。isort的作者Timothy Crosley创建这个工具的原因很有趣:
“在我曾经工作的一个组织中,有一天经理进来决定所有代码必须有按字母顺序排序的导入。代码库很庞大——他的意思是让我们手动完成。然而,作为一个程序员——我太懒了,不愿意花8个小时机械地执行一个功能,但我也不会懒到不愿意花16个小时来自动化它。”
isort的主要功能:
自动排序 :按字母顺序对导入语句进行排序
智能分组 :将导入语句自动分成不同的部分(标准库、第三方库、本地模块等)
多种输出模式 :支持12种不同的多行导入输出格式
高度可配置 :几乎每个方面都可以自定义
格式化前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from my_lib import Objectimport osfrom my_lib import Object3from my_lib import Object2import sysfrom third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14import sysfrom __future__ import absolute_importfrom third_party import lib3print ("Hey" )print ("yo" )
格式化后:
1 2 3 4 5 6 7 8 9 10 11 12 from __future__ import absolute_importimport osimport sysfrom third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14, lib15) from my_lib import Object, Object2, Object3print ("Hey" )print ("yo" )
1.3 为什么需要这些工具?解决哪些痛点? 痛点1:代码风格争论消耗团队精力 在团队开发中,关于代码格式的争论往往是最耗时且最没有意义的:
应该用2空格还是4空格缩进?
单引号还是双引号?
每行最大字符数是80还是120?
导入语句应该如何排序?
这些争论浪费了大量的代码审查时间和团队精力。Black和isort通过提供一个”标准答案”来终结这些争论 ——你可以不同意它们的选择,但至少不用再讨论了。
痛点2:代码审查中的格式噪音 当代码审查中充斥着格式变更时,真正重要的逻辑变更往往被淹没。Black通过保证最小化差异,让代码审查可以专注于实际的代码逻辑改变。
痛点3:新成员入职成本 每个项目都有自己的代码风格指南,新成员需要花费时间学习和适应。使用Black和isort后,代码风格变得统一和自动化,大大降低了入职成本。
痛点4:手动格式化的重复劳动 手动调整代码格式是一项重复、枯燥且容易出错的工作。自动化工具可以在瞬间完成这些工作,让开发者专注于真正重要的事情。
痛点5:导入语句混乱 随着项目的发展,导入语句往往变得越来越混乱:
重复的导入
未使用的导入
没有按照任何逻辑排序
标准库、第三方库、本地模块混在一起
isort通过智能分析和排序,让导入语句变得清晰有序。
二、安装与基本使用 2.1 安装 使用pip安装 1 2 3 4 5 6 7 8 pip install black pip install isort pip install black isort
使用uv安装(推荐) 1 2 3 4 5 6 7 8 uv pip install black uv pip install isort uv add --dev black isort
安装isort的额外功能 1 2 3 4 5 6 7 8 pip install isort[requirements_deprecated_finder] pip install isort[pipfile_deprecated_finder] pip install isort[requirements_deprecated_finder,pipfile_deprecated_finder]
2.2 Black基本使用 格式化单个文件
格式化整个目录
检查代码是否符合格式(不修改文件)
显示格式化差异(不修改文件)
格式化代码字符串 1 2 black --code "print ( 'hello, world' )"
指定行长度 1 black --line-length 120 src/
指定目标Python版本 1 black --target-version py311 --target-version py312 src/
2.3 isort基本使用 排序单个文件的导入
递归排序整个目录
查看将要进行的更改(不修改文件)
检查导入是否已正确排序
原子性运行(只在不引入语法错误时应用更改)
使用Black兼容配置 1 isort --profile black src/
2.4 Python API使用 Black的Python API 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import blackcode = "x = { 'a':37,'b':42, 'c':927}" formatted = black.format_str(code, mode=black.Mode()) print (formatted)black.format_file_in_place( src=Path("myfile.py" ), fast=False , mode=black.Mode(), write_back=black.WriteBack.YES )
isort的Python API 1 2 3 4 5 6 7 8 9 10 11 import isortisort.file("pythonfile.py" ) sorted_code = isort.code("import b\nimport a\n" ) print (sorted_code)
三、配置详解 3.1 Black配置选项 Black的设计理念是”尽量少的配置选项”,因此它的配置项相对较少:
选项
描述
默认值
line-length
每行最大字符数
88
target-version
目标Python版本
自动检测
skip-string-normalization
跳过字符串引号规范化
False
skip-magic-trailing-comma
忽略魔术尾随逗号
False
preview
启用预览样式
False
exclude
排除的文件/目录正则表达式
常见忽略目录
extend-exclude
扩展排除模式
无
force-exclude
强制排除模式
无
include
包含的文件模式
\.pyi?$
行长度的选择 Black默认使用88个字符的行长度,这是一个经过深思熟虑的选择:
比PEP 8推荐的79个字符稍长,减少了换行
比常见的100或120字符短,在并排显示时更友好
10%的额外空间通常可以让格式化后的代码更紧凑
3.2 isort配置选项 isort提供了丰富的配置选项,以下是最常用的:
选项
描述
默认值
profile
预设配置(black, django, google等)
无
line_length
行长度限制
79
multi_line_output
多行输出模式(0-10)
0 (GRID)
include_trailing_comma
包含尾随逗号
False
force_single_line
强制每个导入单独一行
False
known_first_party
标记为第一方的模块
无
known_third_party
标记为第三方的模块
无
skip
跳过的文件/目录
常见忽略目录
skip_glob
跳过的文件模式
无
src_paths
源代码路径
无
sections
导入分组顺序
FUTURE, STDLIB, THIRDPARTY, FIRSTPARTY, LOCALFOLDER
多行输出模式 isort支持12种多行输出模式:
Mode 0 (GRID) :网格布局
Mode 1 (VERTICAL) :垂直布局
Mode 2 (HANGING_INDENT) :悬挂缩进
Mode 3 (VERTICAL_HANGING_INDENT) :垂直悬挂缩进(Black推荐)
Mode 4 (VERTICAL_GRID) :垂直网格
Mode 5 (VERTICAL_GRID_GROUPED) :分组垂直网格
Mode 6-10 :其他变体
3.3 isort内置配置文件(Profiles) isort提供了多个内置配置文件,可以快速适配不同的代码风格:
1 2 3 4 5 6 7 8 9 profile = "black" multi_line_output = 3 include_trailing_comma = True force_grid_wrap = 0 use_parentheses = True ensure_newline_before_comments = True line_length = 88
其他可用的配置文件:
django
pycharm
google
open_stack
plone
attrs
hug
wemake
appnexus
四、与pyproject.toml结合配置 4.1 什么是pyproject.toml? pyproject.toml是由PEP 518定义的Python项目配置文件,用于存储项目的构建系统要求和工具配置。它已经成为现代Python项目的标准配置文件,可以统一管理多个工具的配置,避免配置文件泛滥。
4.2 Black的pyproject.toml配置 在pyproject.toml中,Black的配置位于[tool.black]部分:
1 2 3 4 5 6 7 8 9 [tool.black] line-length = 88 target-version = ['py311' , 'py312' ]include = '\.pyi?$' extend-exclude = ''' # A regex preceded with ^/ will apply only to files and directories # in the root of the project. ^/tests/fixtures/ '''
完整配置示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 [tool.black] line-length = 88 target-version = ['py310' , 'py311' , 'py312' ]skip-string-normalization = false skip-magic-trailing-comma = false preview = false exclude = ''' /( \.eggs | \.git | \.hg | \.mypy_cache | \.tox | \.venv | _build | buck-out | build | dist | migrations )/ ''' extend-exclude = ''' /( tests/fixtures | scripts/legacy )/ '''
4.3 isort的pyproject.toml配置 isort的配置位于[tool.isort]部分:
1 2 3 [tool.isort] profile = "black" line_length = 88
完整配置示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 [tool.isort] profile = "black" line_length = 88 multi_line_output = 3 include_trailing_comma = true use_parentheses = true ensure_newline_before_comments = true force_alphabetical_sort_within_sections = true known_first_party = ["myproject" , "myapp" ]known_third_party = ["requests" , "django" , "flask" ]known_local_folder = ["tests" ]src_paths = ["src" , "tests" ]skip = [".git" , ".venv" , "venv" , "build" , "dist" ]skip_gitignore = true sections = ["FUTURE" , "STDLIB" , "THIRDPARTY" , "FIRSTPARTY" , "LOCALFOLDER" ]lines_between_sections = 1 lines_after_imports = 2 force_single_line = false from_first = false
4.4 Black + isort联合配置 为了确保Black和isort协同工作,需要确保它们的配置兼容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 [project] name = "my-python-project" version = "1.0.0" requires-python = ">=3.10" [tool.black] line-length = 88 target-version = ['py310' , 'py311' , 'py312' ]include = '\.pyi?$' exclude = ''' /( \.eggs | \.git | \.hg | \.mypy_cache | \.nox | \.tox | \.venv | _build | buck-out | build | dist )/ ''' [tool.isort] profile = "black" line_length = 88 known_first_party = ["myproject" ]src_paths = ["src" ]skip_gitignore = true sections = ["FUTURE" , "STDLIB" , "THIRDPARTY" , "FIRSTPARTY" , "LOCALFOLDER" ]import_heading_stdlib = "Standard Library" import_heading_thirdparty = "Third Party" import_heading_firstparty = "My Project"
4.5 配置文件查找顺序 Black的配置查找 Black按以下顺序查找配置文件:
命令行传入的文件及目录的公共基目录开始
向上搜索父目录
直到找到pyproject.toml(包含[tool.black]部分)
或遇到.git/.hg目录
或到达文件系统根目录
全局配置位置(作为fallback):
Windows : ~\.black
Linux/MacOS : $XDG_CONFIG_HOME/black(默认为~/.config/black)
isort的配置查找 isort支持多种配置文件格式,按以下优先级查找:
pyproject.toml([tool.isort]部分)
.isort.cfg
setup.cfg([isort]部分)
tox.ini([isort]部分)
.editorconfig
五、VS Code集成配置 5.1 安装必要的扩展 在VS Code中使用Black和isort,需要安装以下扩展:
Python (ms-python.python) - 微软官方Python扩展
Black Formatter (ms-python.black-formatter) - 官方Black格式化扩展
isort (ms-python.isort) - 官方isort扩展
可以通过VS Code扩展市场搜索安装,或使用命令行:
1 2 3 code --install-extension ms-python.python code --install-extension ms-python.black-formatter code --install-extension ms-python.isort
5.2 配置settings.json 在VS Code的设置文件中添加以下配置:
用户级设置 (User settings.json) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { "[python]" : { "editor.defaultFormatter" : "ms-python.black-formatter" , "editor.formatOnSave" : true , "editor.codeActionsOnSave" : { "source.organizeImports" : "explicit" } } , "black-formatter.args" : [ "--line-length" , "88" ] , "isort.args" : [ "--profile" , "black" ] }
工作区设置 (Workspace .vscode/settings.json) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 { "[python]" : { "editor.defaultFormatter" : "ms-python.black-formatter" , "editor.formatOnSave" : true , "editor.codeActionsOnSave" : { "source.organizeImports" : "explicit" } } , "black-formatter.args" : [ "--config" , "${workspaceFolder}/pyproject.toml" ] , "isort.args" : [ "--settings-path" , "${workspaceFolder}/pyproject.toml" ] , "python.defaultInterpreterPath" : "${workspaceFolder}/.venv/bin/python" }
5.3 详细配置说明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 { "black-formatter.path" : [ ] , "black-formatter.args" : [ "--line-length" , "88" , "--target-version" , "py311" ] , "[jupyter-notebook]" : { "editor.defaultFormatter" : "ms-python.black-formatter" } , "black-formatter.interpreter" : [ ] , "black-formatter.importStrategy" : "useBundled" , "black-formatter.showNotification" : "onError" }
isort扩展配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 { "isort.args" : [ "--profile" , "black" , "--line-length" , "88" ] , "isort.path" : [ ] , "isort.importStrategy" : "useBundled" , "isort.showNotification" : "onError" , "isort.check" : false , "isort.interpreter" : [ ] }
5.4 配置示例:完整的工作区设置 创建.vscode/settings.json文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 { "[python]" : { "editor.defaultFormatter" : "ms-python.black-formatter" , "editor.formatOnSave" : true , "editor.formatOnPaste" : false , "editor.codeActionsOnSave" : { "source.organizeImports" : "explicit" } , "editor.rulers" : [ 88 ] , "editor.tabSize" : 4 , "editor.insertSpaces" : true } , "black-formatter.args" : [ "--config" , "${workspaceFolder}/pyproject.toml" ] , "black-formatter.importStrategy" : "fromEnvironment" , "black-formatter.showNotification" : "onError" , "isort.args" : [ "--settings-path" , "${workspaceFolder}/pyproject.toml" ] , "isort.importStrategy" : "fromEnvironment" , "isort.showNotification" : "onError" , "python.defaultInterpreterPath" : "${workspaceFolder}/.venv/bin/python" , "python.analysis.typeCheckingMode" : "basic" , "python.analysis.autoImportCompletions" : true , "files.associations" : { "*.py" : "python" , "*.pyi" : "python" } , "files.exclude" : { "**/__pycache__" : true , "**/*.pyc" : true , "**/.pytest_cache" : true , "**/.mypy_cache" : true } }
5.5 键盘快捷键配置 在VS Code中,可以为格式化操作设置自定义快捷键:
打开keybindings.json(按Ctrl+K Ctrl+S,然后点击右上角的”打开键盘快捷方式(JSON)”):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [ { "key" : "ctrl+shift+b" , "command" : "editor.action.formatDocument" , "when" : "editorLangId == python" } , { "key" : "ctrl+shift+i" , "command" : "editor.action.organizeImports" , "when" : "editorLangId == python" } , { "key" : "ctrl+shift+alt+f" , "command" : "runCommands" , "args" : { "commands" : [ "editor.action.organizeImports" , "editor.action.formatDocument" ] } , "when" : "editorLangId == python" } ]
5.6 使用任务(Tasks)运行格式化 创建.vscode/tasks.json文件来定义格式化任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 { "version" : "2.0.0" , "tasks" : [ { "label" : "Black: Format Current File" , "type" : "shell" , "command" : "black" , "args" : [ "${file}" ] , "presentation" : { "reveal" : "silent" , "panel" : "shared" } , "problemMatcher" : [ ] } , { "label" : "Black: Format All Files" , "type" : "shell" , "command" : "black" , "args" : [ "." ] , "presentation" : { "reveal" : "always" , "panel" : "shared" } , "problemMatcher" : [ ] } , { "label" : "isort: Sort Current File" , "type" : "shell" , "command" : "isort" , "args" : [ "${file}" ] , "presentation" : { "reveal" : "silent" , "panel" : "shared" } , "problemMatcher" : [ ] } , { "label" : "isort: Sort All Files" , "type" : "shell" , "command" : "isort" , "args" : [ "." ] , "presentation" : { "reveal" : "always" , "panel" : "shared" } , "problemMatcher" : [ ] } , { "label" : "Format: Black + isort" , "type" : "shell" , "command" : "isort . && black ." , "presentation" : { "reveal" : "always" , "panel" : "shared" } , "problemMatcher" : [ ] , "group" : { "kind" : "build" , "isDefault" : true } } , { "label" : "Check: Black + isort" , "type" : "shell" , "command" : "isort --check-only . && black --check ." , "presentation" : { "reveal" : "always" , "panel" : "shared" } , "problemMatcher" : [ ] } ] }
六、高级用法与最佳实践 6.1 Pre-commit集成 使用pre-commit可以在提交代码前自动运行格式化检查:
创建.pre-commit-config.yaml:
1 2 3 4 5 6 7 8 9 10 11 12 repos: - repo: https://github.com/psf/black rev: 24.10 .0 hooks: - id: black language_version: python3.11 - repo: https://github.com/pycqa/isort rev: 5.13 .2 hooks: - id: isort args: ["--profile" , "black" , "--filter-files" ]
安装pre-commit钩子:
1 2 pip install pre-commit pre-commit install
6.2 GitHub Actions集成 创建.github/workflows/lint.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 name: Lint on: push: branches: [main , develop ] pull_request: branches: [main , develop ] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | pip install black isort - name: Check formatting with Black run: black --check --diff . - name: Check import sorting with isort run: isort --check-only --diff --profile black .
6.3 跳过特定代码块 Black跳过格式化 1 2 3 4 5 6 7 8 9 10 11 matrix = [ [1 , 0 , 0 ], [0 , 1 , 0 ], [0 , 0 , 1 ], ] x = [1 ,2 ,3 ]
isort跳过导入排序 1 2 3 4 5 6 7 8 9 """整个文件跳过isort处理""" import bimport aimport specific_module
6.4 处理常见问题 问题1:Black和isort冲突 解决方案:确保isort使用profile = "black"配置:
1 2 [tool.isort] profile = "black"
问题2:Jupyter Notebook格式化 Black支持Jupyter Notebook格式化:
1 black --ipynb notebook.ipynb
在VS Code中配置:
1 2 3 4 5 { "[jupyter-notebook]" : { "editor.defaultFormatter" : "ms-python.black-formatter" } }
问题3:忽略生成的代码 在pyproject.toml中配置:
1 2 3 4 5 6 7 8 9 10 11 [tool.black] extend-exclude = ''' /( migrations | generated | __pycache__ )/ ''' [tool.isort] skip_glob = ["**/migrations/*" , "**/generated/*" ]
6.5 推荐的项目配置模板 完整的pyproject.toml模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 [project] name = "my-project" version = "1.0.0" description = "A Python project" requires-python = ">=3.10" dependencies = [][project.optional-dependencies] dev = [ "black>=24.0.0" , "isort>=5.13.0" , "pre-commit>=3.0.0" , "pytest>=8.0.0" , "mypy>=1.0.0" , ] [tool.black] line-length = 88 target-version = ['py310' , 'py311' , 'py312' ]include = '\.pyi?$' exclude = ''' /( \.eggs | \.git | \.hg | \.mypy_cache | \.nox | \.tox | \.venv | venv | _build | buck-out | build | dist | migrations )/ ''' [tool.isort] profile = "black" line_length = 88 known_first_party = ["myproject" ]known_third_party = ["requests" , "pytest" ]src_paths = ["src" , "tests" ]skip_gitignore = true force_sort_within_sections = true combine_as_imports = true [tool.pytest.ini_options] testpaths = ["tests" ]python_files = ["test_*.py" ]addopts = "-v --tb=short" [tool.mypy] python_version = "3.10" warn_return_any = true warn_unused_configs = true ignore_missing_imports = true
七、总结 7.1 核心要点回顾
Black 是一个”不妥协”的代码格式化工具,通过限制选择来消除格式争论
isort 是一个智能的导入语句排序工具,支持高度定制化
两者可以通过profile = "black"配置完美协作
使用pyproject.toml可以统一管理两个工具的配置
VS Code通过官方扩展提供了开箱即用的支持
7.2 快速开始清单
✅ 安装Black和isort:pip install black isort
✅ 在VS Code中安装官方扩展
✅ 创建pyproject.toml配置文件
✅ 配置VS Code设置启用保存时格式化
✅ (可选)配置pre-commit实现提交前检查
7.3 相关资源
使用Black和isort后,你将体验到:
“格式化变得透明,你可以专注于内容本身。” —— Black官方文档
希望这篇指南能帮助你在Python开发中更高效地使用这两个强大的工具!