Python 语言最明显的特征之一是用缩进量表示从属关系,没有采用 Java, C 用括号定义作用域的自由书写风格。 所以 Python 对代码格式的要求十分严格,社区发展出了完整的编码规范和丰富的检查和修复工具,并能够整合到几乎所有主流编辑器中。
编码规范在提升代码质量和可读性、降低维护成本等方面发挥了核心作用,但如果没有相应的工具链帮助其落地,很难真正产生效果,本文第3、4节专门论述如何搭建可用的工具链。
Python 社区不鼓励对编码规范做人工审查,因为人工审查存在如下问题:
- 成本高:需要人力和时间做代码审查;
- 效果差:很难避免主观判断和遗漏;
- 事后审查:反馈周期长,不能培养开发者良好的编码习惯;
由于上述原因,大多数人工审查最后都会被废弃,或者流于形式,无法产生应有的效果。所以社区的最佳实践是通过工具链做自动编码审查,解决规范的落地问题。
本规范适用于 Python 3.6 及以上版本。
Python 的编码规范由社区官方组织 Python Software Foundation (PSF) 发布的 Python Enhancement Proposal (PEP) 规范文档中的 PEP 8 定义, 适用于所有 Python 开发场景。
Docstring 规范见 PEP 257。
-
使用函数和类型构建程序,尽量不要使用类和继承关系;
-
避免魔法数字,将数字定义为常量;
-
代码嵌套层次不超过3层;
-
单行代码长度不超过 80 个字符;
-
避免使用全局变量;
-
任何名称(包、模块、函数、类、变量)中尽量使用英文,不要使用汉语拼音;
-
使用 docstring 注释模块和函数;
有效的命名风格:
- lowercase
- lower_case_with_underscores
- UPPERCASE
- UPPER_CASE_WITH_UNDERSCORES
- T: 单个大写字母
- CapWords
某些语言可能会使用其他命名风格,例如 mixedCase, Variable-Name, Class_Name, b 等, 但这些风格 Python 不推荐使用。
基本命名规则:
-
Package and Module: 尽量使用 lowercase,可以使用 lower_case_with_underscores
-
Variable: lowercase 或者 lower_case_with_underscores
-
Function and method: lowercase 或者 lower_case_with_underscores
-
Constants: UPPERCASE 或者 UPPER_CASE_WITH_UNDERSCORES
-
Type variable: T 或者 CapWords
-
Class: CapWords
括号两侧不加空格:
Right: spam(ham[1], {eggs: 2})
Wrong: spam( ham[ 1 ], { eggs: 2 } )
Right: dct['key'] = lst[index]
Wrong: dct ['key'] = lst [index]
冒号、逗号、分号前不加空格:
Right: if x == 4: print x, y; x, y = y, x
Wrong: if x == 4 : print x , y ; x , y = y , x
函数和括号间不加空格:
Right: spam(1)
Wrong: spam (1)
操作符两侧加空格:
Right: a = 1 + 2
Wrong: a=1+2
参数赋值的等号两侧不加空格:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
不要写成 imag = 0.0
.
Python 开发者使用 linter 发现编码中的问题,给出错误位置和类型(错误码), 由于大部分问题都有简单直接的修复方法,为了进一步提高效率,社区开发出了 formatter 自动修复无需人工干预就能修复的问题。
Linter 查找两大类问题:
-
逻辑问题:例如使用未被赋值的变量;
-
风格问题:不符合 PEP 8 和 257 的书写方法。
Linter 推荐使用 flake8,它能够同时检查上面两类错误, 并给出 错误编码。
flake8 默认不做命名风格检查,需要安装插件 pep8-naming 实现命名规则检查。
Formatter 推荐使用 Google 的 yapf,定制性好,能够很好地和 flake8 整合在一起。
编辑器整合工具在编辑器后台运行 linter 和 formatter,使开发者在编写代码时即时发现和修复问题。
推荐使用 neovim 作为编辑器,使用 vim-plug 作为插件管理工具,使用 ALE 作为异步 linter 引擎,然后通过如下方式支持 linter 和 formatter:
let g:ale_enabled = 1
let b:ale_linters = {'python': ['flake8']}
let b:ale_fixers = {'python': ['yapf']}
Plug 'w0rp/ale'
Q: 为什么 Python 采用缩进语法?
A: 与括号语法相比,用缩进表示作用域符合人类阅读文本时对语义群的划分。体现了 Python 语言重视代码可读性,认为可读性比编译器解析方便更重要的设计思想。