Python Style Guide
综述
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。
核心原则:
-
程序是由一系列函数和类型 (type) 构成的,尽量使用 expression 代替 statement;
-
FP 优于 OOP,尽量不要使用类 (class) 和继承关系;
-
尽量使用不可变 (immutable) 数据结构,不修改已有变量,而是通过函数调用返回新的变量;
-
尽量不使用 for/while 循环结构,代之以 FP 风格的
map
,reduce
,group_by
等; -
一个有明确业务含义的动作,尽量使用一行代码实现,如果无法实现,通过定义一个语义明确的函数实现;
-
变量/函数的命名应具备明确的业务含义,不要使用有误导性的变量名称;
-
任何名称(包、模块、函数、类、变量)中尽量使用英文及英文缩写命名,不要使用汉语拼音、拼音首字母缩写以及拼音-英文混合命名;
-
避免魔法数字,将数字定义为常量,常量的命名应具备明确的业务含义;
-
代码嵌套层次不超过3层;
-
单行代码长度不超过 80 个字符;
-
避免使用全局变量;
-
保证代码可读性:使用 docstring 注释模块和函数;
-
保证代码正确性:为函数添加 doctest,并保证 doctest 能够通过测试;
命名规则
有效的命名风格:
-
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,使开发者在编写代码时即时发现和修复问题。
vim
推荐使用 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'
编码最佳实践
-
用
logging.debug
取代用于 debug 和调试的print
语句; -
导入外部文件时尽量使用相对路径,代码任何位置,包括注释中,不允许出现个人开发环境的绝对文件路径;
附录
Q: 为什么 Python 采用缩进语法?
A: 与括号语法相比,用缩进表示作用域符合人类阅读文本时对语义群的划分。体现了 Python 语言重视代码可读性,认为可读性比编译器解析方便更重要的设计思想。