Python `black` / `isort`:代码格式化与自动导入排序

好的,各位观众老爷们,欢迎来到今天的“代码美容院”!今天咱们要聊聊两款神器,它们能让你的代码瞬间变美,告别“屎山”,走向优雅。它们就是:blackisort

一、代码的“面子”问题:为什么需要格式化?

咱们先来唠唠嗑,扪心自问一下:你的代码,自己看着舒服吗?

如果你写代码像挤牙膏,想到哪儿写到哪儿,空格乱飞,缩进混乱,那… 咳咳,很可能你的代码“颜值”不太高。

代码的“颜值”很重要吗? 非常重要!它直接影响了:

  • 可读性: 整洁的代码更容易阅读和理解,别人(包括未来的你)才能快速上手。
  • 可维护性: 风格一致的代码更容易修改和维护,bug 少,头发保得住。
  • 团队协作: 统一的代码风格能避免撕逼,让团队成员专注于业务逻辑,而不是争论空格数量。

所以,代码格式化,不仅是“面子”问题,更是“里子”问题!

二、black:代码界的“Tony 老师”

black 是一款“不妥协的代码格式化工具”。 啥叫“不妥协”? 就是说,它有一套自己的审美标准,会强制把你的代码格式化成它认为最好的样子。

black 的好处是:你不需要操心代码风格,只需要专注于业务逻辑。它会帮你处理所有格式细节,比如:

  • 空格
  • 换行
  • 字符串引号
  • 等等…

black 的哲学是:少即是多。 它会尽量简化你的代码,让它更易读。

1. 安装 black

pip install black

2. 使用 black

假设我们有这样一个“丑陋”的 Python 文件 ugly.py

def my_function(arg1, arg2, arg3):
  if (arg1 > 10 and
      arg2 < 20):
    return     "hello"    +    "world"
  else:
    return 'goodbye'

执行 black ugly.py

black ugly.py
reformatted ugly.py
All done! ✨ 🍰 ✨
1 file reformatted.

再看看 ugly.py 的内容:

def my_function(arg1, arg2, arg3):
    if arg1 > 10 and arg2 < 20:
        return "hello" + "world"
    else:
        return "goodbye"

是不是瞬间清爽多了? black 自动帮我们做了:

  • 函数定义处的空格
  • if 条件的括号
  • 字符串的引号
  • return 语句的空格
  • 等等…

3. black 的常用选项

  • --line-length <int>:指定每行最大长度,默认是 88。
  • --target-version <version>:指定目标 Python 版本,比如 py37
  • --include <regex>:指定需要格式化的文件,可以使用正则表达式。
  • --exclude <regex>:指定不需要格式化的文件,可以使用正则表达式。
  • --check:只检查代码是否需要格式化,不实际修改文件。
  • --diff:显示格式化前后的差异。

例如,检查 ugly.py 是否需要格式化:

black --check ugly.py
Would reformat ugly.py
1 file would be reformatted

显示格式化前后的差异:

black --diff ugly.py
--- a/ugly.py
+++ b/ugly.py
@@ -1,6 +1,6 @@
 def my_function(arg1, arg2, arg3):
-  if (arg1 > 10 and
-      arg2 < 20):
-    return     "hello"    +    "world"
-  else:
-    return 'goodbye'
+    if arg1 > 10 and arg2 < 20:
+        return "hello" + "world"
+    else:
+        return "goodbye"

4. 集成到 IDE

几乎所有主流 IDE 都支持 black,可以配置成保存时自动格式化代码。 例如,VS Code 可以安装 Python 扩展,然后在 settings.json 中添加:

{
    "python.formatting.provider": "black",
    "editor.formatOnSave": true
}

三、isort:导入模块的“收纳师”

isort 是一款专门用来排序 Python 导入模块的工具。

Python 的导入模块,就像你的衣柜,如果乱七八糟,找东西就很麻烦。 isort 可以帮你把它们整理得井井有条,让你的代码更易读。

1. 安装 isort

pip install isort

2. 使用 isort

假设我们有这样一个 Python 文件 messy_imports.py

import os
from flask import Flask
import sys
import requests
from collections import defaultdict

def my_function():
    pass

执行 isort messy_imports.py

isort messy_imports.py
Fixing /path/to/messy_imports.py

再看看 messy_imports.py 的内容:

from collections import defaultdict
from flask import Flask
import os
import requests
import sys

def my_function():
    pass

isort 自动帮我们做了:

  • from 导入放在前面
  • 按字母顺序排序模块
  • 在不同的导入类型之间添加空行

isort 默认的排序规则是:

  1. 标准库模块
  2. 第三方模块
  3. 本地模块

3. isort 的常用选项

  • --profile <profile>:指定预定义的配置,比如 black,可以和 black 配合使用。
  • --multi-line <mode>:指定多行导入的格式,比如 vertical-grid
  • --line-width <int>:指定每行最大长度,默认是 79。
  • --atomic:确保文件要么完全格式化,要么不修改。
  • --check-only:只检查导入模块是否需要排序,不实际修改文件。
  • --diff:显示排序前后的差异。

例如,使用 black 的配置:

isort --profile black messy_imports.py

显示排序前后的差异:

isort --diff messy_imports.py
--- a/messy_imports.py
+++ b/messy_imports.py
@@ -1,12 +1,13 @@
+from collections import defaultdict
+from flask import Flask
 import os
-from flask import Flask
+import requests
 import sys
-import requests
-from collections import defaultdict
+

 def my_function():
     pass

4. .isort.cfg 配置文件

isort 可以通过 .isort.cfg 文件进行配置。 在项目根目录下创建 .isort.cfg 文件,例如:

[settings]
profile = black
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0

这个配置指定了:

  • 使用 black 的配置
  • 多行导入使用垂直网格格式
  • 包含尾随逗号
  • 不强制使用网格换行

5. 集成到 IDE

black 类似,几乎所有主流 IDE 都支持 isort,可以配置成保存时自动排序导入模块。

四、black + isort:珠联璧合,天下无敌

black 负责代码格式化,isort 负责导入模块排序,两者配合使用,可以打造出完美的代码风格。

1. 配合使用的方式

最简单的方式是:先运行 isort,再运行 black

isort .
black .

或者,可以使用 pre-commit 钩子,在提交代码前自动运行 blackisort

2. pre-commit 钩子

pre-commit 是一个用于管理 Git 预提交钩子的工具。它可以让你在提交代码前自动运行各种检查,比如代码格式化、代码风格检查、单元测试等等。

安装 pre-commit

pip install pre-commit

创建 .pre-commit-config.yaml 文件:

在项目根目录下创建 .pre-commit-config.yaml 文件,添加以下内容:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
  - repo: https://github.com/PyCQA/isort
    rev: 5.12.0
    hooks:
      - id: isort
        name: isort (python)
  - repo: https://github.com/psf/black
    rev: 23.3.0
    hooks:
      - id: black

这个配置指定了:

  • 使用 pre-commit-hooks 仓库中的一些常用钩子,比如去除行尾空格、添加文件结尾空行、检查 YAML 文件等等。
  • 使用 isort 仓库中的 isort 钩子,用于排序导入模块。
  • 使用 black 仓库中的 black 钩子,用于格式化代码。

安装 pre-commit 钩子:

pre-commit install

现在,每次提交代码前,pre-commit 都会自动运行这些钩子。 如果代码不符合要求,提交会被阻止,你需要先修复代码。

五、一些注意事项

  • 团队统一: 在团队中使用 blackisort 时,一定要统一配置,避免出现代码风格不一致的情况。
  • 版本控制:.isort.cfg.pre-commit-config.yaml 文件纳入版本控制,确保团队成员使用相同的配置。
  • 逐步引入: 如果你的项目已经很大,一下子全部用 black 格式化可能会导致大量的代码变更。 可以逐步引入,先格式化部分文件,再逐步扩大范围。
  • 特殊情况: 有时候,blackisort 的格式化结果可能不符合你的预期。 你可以使用 # fmt: off# fmt: on 注释来禁用部分代码的格式化。
  • 持续集成: 可以在持续集成 (CI) 系统中集成 blackisort,确保每次代码提交都符合代码风格要求。

六、总结

blackisort 是两款非常强大的代码格式化工具,可以帮助你打造出优雅的代码风格。 它们的使用非常简单,配置也很灵活。 强烈建议你在项目中使用它们,让你的代码更易读、更易维护、更漂亮!

工具 功能 优点 缺点
black 代码格式化 强制统一风格,配置简单,易于集成 过于“不妥协”,可能不符合所有人的审美
isort 导入模块排序 自动排序导入模块,提高代码可读性 需要配置,默认规则可能不符合所有项目需求
black + isort 代码格式化 + 导入模块排序 完美的代码风格,提高代码质量,减少代码审查时间,提高团队协作效率 需要一定的学习成本,需要统一配置,可能需要逐步引入到现有项目中

好了,今天的“代码美容院”就到这里了。 希望大家都能用上 blackisort,让自己的代码变得更美! 谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注