Python3:开发编码规范常用工具介绍

Python 赢得众人喜爱的重要原因有很多:简洁的语法、强大的标准库以及极低的上手成本,你既可以用它来写一些快糙猛的小脚本,同时也能用它来做一些真正的“大项目”,解决一些更为复杂的问题,总结下Python的主要特点有:

  1. 易学易用:Python 的语法简洁明了,接近自然语言,非常适合初学者。它的代码可读性强,开发者能够更快地上手和实现复杂功能。

  2. 丰富的库和框架:Python 拥有庞大的标准库和第三方库,涵盖了从数据分析、机器学习、Web 开发到自动化脚本等各个领域。例如,NumPy 和 Pandas 是数据处理的利器,TensorFlow 和 PyTorch 是深度学习的主流框架,Django 和 Flask 是流行的 Web 开发框架。

  3. 广泛的应用领域:Python 被广泛应用于数据科学、人工智能、Web 开发、自动化测试、系统运维等多个领域。其通用性使得它在各个行业都能找到合适的应用场景。

  4. 社区活跃:Python 拥有一个庞大且活跃的社区,开发者可以通过论坛、博客、在线教程等途径获得大量的资源和帮助。这种强大的社区支持也是推动 Python 发展的重要因素。

  5. 跨平台性:Python 是跨平台的语言,可以运行在 Windows、MacOS、Linux 等操作系统上,这使得开发者可以更方便地在不同环境中部署和运行 Python 程序。

  6. 大公司的支持:许多大型科技公司,如谷歌、脸书、亚马逊等,都在使用 Python 并为其生态系统贡献力量,这无疑增强了 Python 的影响力和可信度。

  7. 面向对象和函数式编程:Python 支持多种编程范式,包括面向对象编程和函数式编程,这使得开发者可以选择最适合自己项目的编程风格。

写个几百行代码的 Python 脚本是一码事,参与一个有数万行代码的项目,用它来服务成千上万的用户则完全是另一码事。当项目规模变大,参与人数变多后,许多在写小脚本时完全不用考虑的问题会跳出来:

  • 缩进用 Tab 还是空格?如何让所有人的代码格式保持统一?
  • 为什么每次发布新版本都心惊胆战?如何在代码上线前发现错误?
  • 如何在快速开发新功能的同时,对代码做安全重构?

一、常用工具介绍

在开发中大型项目时,往往需要多人参与,甚至跨团队合作。试想一下,如果每个人都按照自己的编码习惯和风格来,那简直是个灾难,最后的代码肯定破碎不堪、难以入目。因此在多人参与的大型项目里,最基本的一件事就是让所有人的代码风格保持一致,整洁得就像是出自同一人之手。

下面抛砖引玉介绍几个与代码风格有关的工具。如果能让所有开发者都使用这些工具,你就可以轻松统一项目的代码风格,内容简介:

  • flake8、isort、black:常用的代码检查与格式化工具。
  • pre-commit:一个专门用于预提交阶段的工具,根据设置好的检查规则(如:flake8、isort、black),对用户提交的修改代码进行格式化检查,如果没有通过会阻塞提交,屏蔽用户编码习惯的差异,比如不同的人一般会使用不同的IDE,甚至有的人用Vim编程。

1、flake8

Python 有一份官方代码风格指南:PEP 8。PEP 8 对代码风格提出了许多具体要求,比如每行代码不能超过 79 个字符、运算符两侧一定要添加空格,等等。

在开发项目时,光有一套纸面上的规范是不够的。纸面规范只适合阅读,无法用来快速检验真实代码是否符合规范。只有通过自动化代码检查工具(常被称为 Linter)才能最大地发挥 PEP 8 的作用。

flake8 就是这么一个工具。利用 flake8,你可以轻松检查代码是否遵循了 PEP 8 规范

1.1 安装flake8

pip3 install flake8

1.2 基本用法

在终端中直接运行 flake8 即可检查单个文件或整个目录:

# 检查单个文件
flake8 example.py

# 检查整个目录
flake8 my_project/

1.3 输出示例

flake8 会输出代码中不符合 PEP 8 规范的地方,示例:

example.py:1:1: F401 'os' imported but unused
example.py:2:5: E225 missing whitespace around operator
example.py:5:1: E302 expected 2 blank lines, found 1

1.4 配置flake8

你可以通过在项目根目录下创建一个配置文件 .flake8setup.cfg 来配置 flake8 的行为。下面是一个 .flake8 配置文件的示例:

[flake8]
max-line-length = 88
exclude = .git,__pycache__,old,build,dist

1.5 忽略特定规则

flake8 为每类错误定义了不同的错误代码,比如 F401、E111 等。这些代码的首字母代表了不同的错误来源,比如以 E 和 W 开头的都违反了 PEP 8 规范,以 F 开头的则来自于 pyflakes。

如果你想忽略某些特定的 PEP 8 规则,可以在命令行中使用 --ignore 选项:

flake8 example.py --ignore=E501

或者在配置文件中添加:

[flake8]
ignore = E501

1.6 在代码中忽略特定行

import os  # noqa: F401

x = 1+2  # noqa: E225

1.7 示例项目

假设有一个简单的项目结构如下:

my_project/
    example.py
    .flake8

example.py 内容:

import os

def my_function():
    x =1+2
    return x

.flake8 内容:

[flake8]
max-line-length = 88
exclude = .git,__pycache__,old,build,dist
ignore = E225

运行 flake8 my_project/,输出如下:

my_project/example.py:1:1: F401 'os' imported but unused

2、isort

PEP 8 认为,一个源码文件内的所有 import 语句,都应该依照以下规则分为三组,不同的 import 语句组之间应该用空格分开

(1) 导入 Python 标准库包的 import 语句;

(2) 导入相关联的第三方包的 import 语句;

(3) 与当前应用(或当前库)相关的 import 语句(本地包)

isort 是一个用于自动整理 Python 导入语句(import)的工具,它可以根据配置文件或默认规则将导入语句排序并分组。借助 isort,我们不用手动进行任何分组,它会帮我们自动做好这些事。

总之,有了 isort 以后,你在调整 import 语句时可以变得随心所欲,只需负责一些简单的编辑工作,isort 会帮你搞定剩下的所有事情——只要执行 isort,整段 import 代码就会自动变得整齐且漂亮。

2.1 安装

pip3 install isort

2.2 基本用法

在终端中运行 isort 来自动整理单个文件或整个目录的导入语句:

# 整理单个文件
isort example.py

# 整理整个目录
isort my_project/

2.3 示例代码

假设你有一个未整理的 Python 文件 example.py

import sys
import os
from datetime import datetime
import numpy as np
from my_local_module import my_function
import requests
from django.conf import settings

运行 isort example.py 后,isort 会将导入语句整理为:

import os
import sys
from datetime import datetime

import numpy as np
import requests
from django.conf import settings

from my_local_module import my_function

2.4 配置 isort

你可以通过在项目根目录下创建一个配置文件 .isort.cfgpyproject.toml 来配置 isort 的行为。下面是 .isort.cfg 的一个示例:

[settings]
profile = black
line_length = 88
known_third_party = numpy,requests,django
known_first_party = my_local_module

如果使用 pyproject.toml,可以这样配置:

[tool.isort]
profile = "black"
line_length = 88
known_third_party = ["numpy", "requests", "django"]
known_first_party = ["my_local_module"]

 2.5 常用命令和选项

  • 检查模式:只检查导入语句是否已整理,而不直接修改文件
isort --check-only example.py
  • 显示 diff:显示文件整理前后的差异。
isort --diff example.py
  • 使用特定配置文件
isort --settings-path .isort.cfg example.py

3、black

PEP 8 规范为许多代码风格问题提供了标准答案,但这份答案其实非常宏观,在许多细节要求上并不严格。在许多场景中,同一段代码在符合 PEP 8 规范的前提下,可以写成好几种风格。

以下面的代码为例,同一个方法调用语句可以写成三种风格,假如你用 flake8 来扫描上面这三段代码,会发现它们虽然风格迥异,但全都符合 PEP 8 规范。

第一种风格:在不超过单行长度限制时,把所有方法参数写在同一行。

User.objects.create(name='piglei', gender='M', lang='Python', status='active')

第二种风格:在第二个参数时折行,并让后面的参数与之对齐。

User.objects.create(name='piglei',
                    gender='M',
                    language='Python',
                    status='active')

第三种风格:统一使用一层缩进,每个参数单独占用一行。

User.objects.create(
    name='piglei',
    gender='M',
    language='Python',
    status='active'
)

具体哪种风格其实没有好坏之分,一切都只与个人喜爱有关,但是这种差异可能会给项目带来不必要的沟通成本,影响开发效率。

假设你喜欢第一种编码风格:只要函数参数没超过长度限制,就坚决都放在一行里。某天你在开发新功能时,给函数调用增加了一些新参数,修改后发现新代码的长度超过了最大长度限制,于是手动对所有参数进行折行、对齐,整个过程即机械又麻烦。

因此,在多人参与的项目中,除了用 flake8 来扫描代码是否符合 PEP 8 规范外,推荐一个更为激进的代码格式化工具:black。black 是个非常强势的代码格式化工具,基本没有任何可定制性。

black 用起来很简单,只要执行 black 命令即可。

3.1 安装 black

pip3 install black

3.2 基本用法

在终端中运行 black 来格式化单个文件或整个目录:

# 格式化单个文件
black example.py

# 格式化整个目录
black my_project/

3.3 示例代码

假设你有一个未格式化的 Python 文件 example.py

def example_function(param1,param2,param3):
    if param1:print("Hello, world!")
    else:
      print("Goodbye, world!")
    return {'key1':param1,'key2':param2,'key3':param3}

运行 black example.py 后,black 会将代码格式化为:

def example_function(param1, param2, param3):
    if param1:
        print("Hello, world!")
    else:
        print("Goodbye, world!")
    return {"key1": param1, "key2": param2, "key3": param3}

3.4 配置 black

black 默认情况下不需要配置即可使用,但你可以通过 pyproject.toml 文件进行配置。在项目根目录下创建一个 pyproject.toml 文件,并添加以下内容:

[tool.black]
line-length = 88
target-version = ['py37']
exclude = '''
/(
    \.git
  | \.venv
  | build
  | dist
)/
'''

3.5 常用选项

  • 检查模式:只检查代码是否符合 black 的格式,而不修改文件。
black --check example.py
  • 显示差异:显示文件格式化前后的差异。
black --diff example.py
  • 只格式化特定版本的代码:指定目标 Python 版本。
black --target-version py37 example.py

作为一个代码格式化工具,black 最大的特点在于它的不可配置性。正如官方介绍所言,black 是一个“毫不妥协的代码格式化工具”(The Uncompromising Code Formatter)。

和许多其他格式化工具相比,black 的配置项可以用“贫瘠”两个字来形容。除了单行长度以外,你基本无法对 black 的行为做任何调整。

配置项说明
-l / --line-length允许的最大单行宽度,默认为 88
-S / --skip-string-normalization是否关闭调整字符串引号

在某些人看来,这种设计理念免去了配置上的许多麻烦,非常省心。而对于另一部分人来说,这种不支持任何个性化设置的设计,令他们完全无法接受。

从另一个角度看,虽然 black 格式化过的代码并非十全十美,肯定不能在所有细节上让大家都满意,但它确实能让我们不用在各种编码风格间纠结,能有效解决许多问题。整体来看,在大型项目中引入 black,利远大于弊。

4、pre-commit

前面介绍了几个常用的代码检查与格式化工具。偶尔手动执行那么一两次是远远不够的。要最大地发挥工具的能力,你必须让它们融入所有人的开发流程里。这意味着,对于项目的每位开发者来说,无论是谁改动了代码,都必须保证新代码一定被 black 格式化过,并且能通过 flake8 的检查。

虽然我们没法统一每个人的 IDE,但至少大部分项目使用的版本控制软件是一样的——Git。而 Git 有个特殊的钩子功能,它允许你给每个仓库配置一些钩子程序(hook),之后每当你进行特定的 Git 操作时——比如 git commit、git push,这些钩子程序就会执行。

pre-commit 就是一个基于钩子功能开发的工具。从名字就能看出来,pre-commit 是一个专门用于预提交阶段的工具。要使用它,你需要先创建一个配置文件 .pre-commit-config.yaml。

fail_fast: true
repos:
- repo: https://github.com/timothycrosley/isort
  rev: 5.7.0
  hooks:
  - id: isort
    additional_dependencies: [toml]
- repo: https://github.com/psf/black
  rev: 20.8b1
  hooks:
  - id: black
    args: [--config=./pyproject.toml]
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v2.4.0
  hooks:
  - id: flake8

在上面的配置文件里,我定义了 isort、black、flake8 三个插件。基于这份配置,每当我修改完代码,执行 git commit 时,这些插件就会由 pre-commit 依次触发执行:

$ git commit -m 'Update'
isort...................................Passed 
black...................................Passed
Flake8..................................Passed

[dev fac43421] Update
 1 file changed, 1 insertion(+), 1 deletion(-)

假如某次改动后的代码无法通过 pre-commit 检查,这次提交流程就会中断。此时作者必须修正代码使其符合规范,之后再尝试提交。由于 pre-commit 的配置文件与项目源码存放在一起,都在代码仓库中,因此项目的所有开发者天然共享 pre-commit 的插件配置,每个人不用单独维护各自的配置,只要安装 pre-commit 工具就行。

使用 pre-commit,你可以让代码检查工具融入每位项目成员的开发流程里。所有代码改动在被提交到 Git 仓库前,都会经工具的规范化处理,从而真正实现项目内代码风格的统一。

二、思考说明

上面介绍了一些比较常见的编码编码格式规范检查工具,事实上远远不止这些,还有许多可以关注的点,比如:mypy工具、单元测试等。

不管怎么样,在日常的工作中按实际需求灵活运用,避免教条主义

参考资料:

1、《Python 工匠:案例、技巧与工程实践》,朱雷

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rs勿忘初心

您的鼓励将是我的最大创动原动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值