2020-08-12
PEP8 编程风格规范
代码布局 (Code Lay-Out)
1. 缩进 (Indentation)
- 每个缩进级别 4个 空格
- 连续行所包装元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 同开始分界符(左括号)对齐
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 续行多缩进一级以同其他代码区别
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# 悬挂缩进需要多缩进一级
foo = long_function_name(
var_one, var_two,
var_three, var_four)- Python隐式续行
垂直对齐于圆括号、方括号和花括号
- 悬挂缩进
第一行不应该包括参数,并且在续行中 (续行来说,4空格的规则可以不遵守) 需要再缩进一级以便清楚表示
- Python隐式续行
- 多行结束右圆/方/花括号可以单独一行书写,和上一行的缩进对齐;也可以和多行开始的第一行的第一个字符对齐
1
2
3
4
5
6
7
8
9
10
11
12my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
my_list = [
1, 2, 3,
4, 5, 6,
] - 推荐使用空格来进行缩进。Python 3不允许tab和空格混合使用。
2. 每行最大长度(Maximum Line Length)
- 所有行都限制在 79 个字符以内
- 连续大段的文字(比如文档字符串(docstring)或注释),其结构上的限制更少,这些行应该被限制在72个字符长度内。
- 换行方式是利用Python圆括号、方括号和花括号中的隐式续行。长行可以通过在括号内换行来分成多行。应该最好加上反斜杠来区别续行。
3. 二元运算符之前还是之后换行?
- Kunth 风格: 尽管在段落中的公式总是在二元运算符之后换行,但显示公式时总是在二元运算符之前换行
- 如果项目约定,也可以在二元运算符之后换行
4. 空行 (支持control + L 换行符作为空格)
- 使用 2个 空行来分隔最外层的 函数(function) 和 类(class) 定义
- 使用 1个 空行来分隔 类中的方法(method) 定义
- 额外的空行(尽量少) 来分隔一组相关的函数
- 在函数内使用空行(尽量少) 使代码逻辑更加清晰
5. 源文件编码(Source File Encoding)
- python 2 使用 ASCII
- python 3 使用 UTF-8
- Python标准库中的所有标识符都必须只采用ASCII编码的标识符,在可行的条件下也应当使用英文词
6. 模块引用(Imports)
imports 分行写,不应都写在一行
1
2
3
4# 分开写
import os
# 被允许的
from subprocess import Popen, PIPEimports 写在代码文件的开头,位于模块(module)注释和文档字符串(docstring)之后,模块全局变量(globals)和常量(constants)声明之””.
imports 顺序 (不同的 imports 之间用空格隔开)
- 标准库 imports
- 相关第三方 imports
- 本地应用/库的特定 imports
推荐使用绝对(absolute) imports (易读且会报错)
from mypkg import sibling
显式的相对imports也是一种可以接受的替代方式.特别是当处理复杂的包布局(package layouts)时,采用绝对imports会显得啰嗦.
from .sibling import example
标准库代码应当一直使用绝对imports,避免复杂的包布局.
隐式的相对imports应该永不使用,并且Python 3中已经被去掉了.如果从包含类的模块import的类与本地命名产生冲突,可以直接 import 模块
避免使用通配符进行 imports, 会产生许多不必要的麻烦
7. 模块级的双下划线命名(Module level dunder names)
- 模块及级下划线命名的变量,函数,应该在 文档的多行注释字符串之后
8. 字符串的引用(String Quotes)
- 当字符串中包含单引号时,采用双引号来表示字符串,可以避免使用反斜杠,代码也更易读
- 在一个项目中最好字符串都用单引号或者双引号
9. 表达式和语句中的空格(Whitespace In Expressions And Statements)
- 方括号、圆括号和花括号之后避免使用空格
- 逗号,分号或冒号之前避免使用空格
- 切片操作时避免使用空格
- 冒号和二元运算符是一样的,应该在其左右两边保留相同数量的空格;
- 扩展切片操作中,所有冒号的左右两边空格数都应该相等;
- 切片操作中的参数被省略时,应该也忽略空格.
- 调用函数时传递参数list的括号之前避免使用空格
- 索引和切片操作的左括号之前避免使用空格
- 赋值(或其他)运算符周围使用多个空格来和其他语句对齐
- 避免任何行末的空格.
- 二元运算符的两边都使用一个空格:赋值运算符(=),增量赋值运算符(+=, -= etc.),比较运算符(==, <, >, !=, <>, <=, >=, in, not in, is, is not),布尔运算符(and, or, not).
- 优先级不同的运算符,则在优先级较低的操作符周围增加空白.(不要用超过1个空格,永远保持二元运算符两侧的空白数量一样.)
- 使用=符号来表示关键字参数或参数默认值时,不要在其周围使用空格.
- 函数注解中的:也遵循一般的:加空格的规则,在->两侧各使用一个空格.
- 在组合使用函数注解和参数默认值时,需要在=两侧各使用一个空格(只有当这个参数既有函数注解,又有默认值的时候).
- 复合语句(即将多行语句写在一行)一般是不鼓励使用的.
- 短小的if/for/while中的语句写在一行,多分支的不要使用
10. 何时在末尾加逗号(When to use trailing commas)
- 定义单元素元组(tuple)时是必需的
1
FILES = ('setup.cfg',)
- 在将来有可能扩展的列表末尾添加冗余的逗号,每一个元素写在单独的一行,并在行尾添加逗号,右括号单独占一行.
1
2
3
4FILES = [
'setup.cfg',
'tox.ini',
]
11. 注释(Comments)
- 当代码有改动时,一定要优先更改注释使其保持最新.
- 注释应该是完整的多个句子.如果注释是一个短语或一个句子,其首字母应该大写,除非开头是一个以小写字母开头的标识符(永远不要更改标识符的大小写).
- 注释很短,结束的句号可以被忽略.块注释通常由一段或几段完整的句子组成,每个句子都应该以句号结束.
- 在句尾的句号后再加上2个空格.
- 尽量用英文写注释
- 块注释(Block Comments)
- 一般写在对应代码之前,并且和对应代码有同样的缩进级别.块注释的每一行都应该以#和一个空格开头(除非该文本是在注释内缩进对齐的).
- 行内注释(Inline Comments)
- 尽量少用行内注释.
1
x = x + 1 # x自加
- 行内注释是和代码语句写在一行内的注释.行内注释应该至少和代码语句之间有两个空格的间隔,并且以#和一个空格开始.
- 尽量少用行内注释.
- 文档字符串注释(Documentation Strings)
- 所有的公共模块,函数,类和方法都应该有文档字符串.对于非公共方法,文档字符串不是必要的,但你应该留有注释说明该方法的功能,该注释应当出现在def的下一行.
- 多行文档字符串以单行”””结尾,不能有其他字符
- 对于仅有一行的文档字符串,结尾处的”””应该也写在这一行.
12. 命名约定(Naming Conventions)
首要原则(Overriding Principle)
- 对于用户可见的公共部分API,其命名应当表达出功能用途而不是其具体的实现细节.
命名风格(Descriptive: Naming Styles)
- CapitalizedWords (也叫做CapWords或者CamelCase – 因为单词首字母大写看起来很像驼峰).也被称作StudlyCaps.
注意:当CapWords里包含缩写时,将缩写部分的字母都大写.HTTPServerError比HttpServerError要好. - mixedCase (注意:和CapitalizedWords不同在于其首字母小写!)
- Capitalized_Words_With_Underscores (这种风格超丑!)
- UPPER_CASE_WITH_UNDERSCORES(带下划线大写)
- UPPERCASE(大写)
- lower_case_with_underscores(带下划线小写)
- lowercase(小写)
- B (单个大写字母)
- b (单个小写字母)
- 特殊形式
- _single_leading_underscore: 以单个下划线开头是”内部使用”的弱标志。
- single_trailing_underscore_: 以单个下划线结尾用来避免和Python关键词产生冲突
1
class_="xxx"
- double_leading_underscore: 以双下划线开头的风格命名类属性表示触发命名修饰(在FooBar类中,boo命名会被修饰成_FooBar__boo)
- double_leading_and_trailing_underscore: 以双下划线开头和结尾的命名风格表示“魔术”对象或属性,存在于用户控制的命名空间(user-controlled namespaces)里
- CapitalizedWords (也叫做CapWords或者CamelCase – 因为单词首字母大写看起来很像驼峰).也被称作StudlyCaps.
命名约定(Prescriptive: Naming Conventions)
- 需要避免的命名(Names To Avoid)
- 字符’l’(L的小写的字母)
- ’O’(o大写的字母)
- ’I’(i的大写的字母)
- ASCII兼容性(ASCII Compatibility)
- 包和模块命名(Package And Module Names)
- 模块命名应短小,且为全小写.若下划线能提高可读性,也可以在模块名中使用
- 包命名也应该短小,且为全小写,但不应使用下划线.
- 使用C或C++写的扩展模块有相应的Python模块提供更高级的接口时, C/C++模块名以下划线开头(例如,_sociket)
- 类命名(Class Names)
- 驼峰(CapWords)的命名约定
- 类型变量命名(Type variable names)
- 类型变量名称通常应使用简短的驼峰命名
- 异常命名(Exception Names)
- 类命名约定也适用与异常.不同的是,如果异常实际上是抛出错误的话,异常名前应该加上”Error”的前缀.
- 函数命名(Function Names)
- 函数命名应该都是小写,必要时使用下划线来提高可读性.
- 全局变量命名(Global Variable Names)
- 引用方式设计为from M import *的模块,应该使用all机制来避免import全局变量,或者采用下划线前缀的旧约定来命名全局变量,从而表明这些变量是“模块非公开的”.
- 函数和方法参数(Function And Method Arguments)
- 实例方法的第一参数永远都是self.
- 类方法的第一个参数永远都是cls.
- 在函数参数名和保留关键字冲突时,相对于使用缩写或拼写简化,使用以下划线结尾的命名一般更好.比如,class_比clss更好.
- 方法命名和实例变量(Method Names And Instance Variables)
- 使用函数命名的规则:小写单词,必要时使用下划线分开以提高可读性.
- 仅对于非公开方法和变量命名在开头使用一个下划线
- 避免和子类的命名冲突,使用两个下划线开头来触发Python的命名修饰机制.
- 需要避免的命名(Names To Avoid)
常量(Constants)
- 常量通常是在模块级别定义的,使用全部大写并用下划线将单词分开.如:MAX_OVERFLOW和TOTAL .
13. 公开和内部接口(Public And Internal Interfaces)
- 任何向后兼容性保证仅对公开接口适用
- 文档化的接口被认为是公开的,除非文档中明确申明了它们是临时的或者内部接口,不保证向后兼容性.所有文档中未提到的接口应该被认为是内部的.
- 为了更好审视公开接口和内部接口,模块应该在all属性中明确申明公开API是哪些.将all__设为空list表示该模块中没有公开API.
14. 编程建议(Programming Recommendations)
- 代码应该以不影响其他Python实现(PyPy,Jython,IronPython,Cython,Psyco等)的方式编写.
- 库中性能敏感的部分,用’’.join形式来代替.这会确保在所有不同的实现中字符串拼接是线性时间的.
- 不要依赖于 CPython 在字符串拼接时的优化实现
- 与单例作比较,像None应该用is或is not,从不使用==操作符
- 用is not操作符而不是not … is.虽然这两个表达式是功能相同的,前一个是更可读的,是首选.
- 始终使用def语句来代替直接绑定了一个lambda表达式的赋值语句.
- 捕获异常时,尽可能使用明确的异常,而不是用一个空的except:语句.(限制使用空except语句)
- 绑定异常给一个名字时,最好使用 Python 2.6 里添加的明确的名字绑定语法:
- 对于所有try / except子句,将try子句限制为必需的绝对最小代码量.同样,这样可以避免屏蔽错误.
- 坚持使用return语句.函数内的return语句都应该返回一个表达式,或者None.如果一个return语句返回一个表达式,另一个没有返回值的应该用return None清晰的说明,并且在一个函数的结尾应该明确使用一个return语句(如果有返回值的话).
- 用字符串方法代替字符串模块.
- 用’’.startswith()和’’.endswith()代替字符串切片来检查前缀和后缀.startswith()和endswith()是更简洁的,不容易出错的.
- 对象类型的比较应该始终使用isinstance()而不是直接比较.
- 对于序列(字符串、列表、元组)来说,空的序列为False:
- 对于序列(字符串、列表、元组)来说,空的序列为False:
- 不要让字符串对尾随的空格有依赖.这样的尾随空格是视觉上无法区分的,一些编辑器(或者,reindent.py)会将其裁剪掉.
- 不要用==比较True和False.