代码布局
缩进
- 每一行缩进使用四个空格
- 延续行
与圆括号、方括号和花括号内的左部垂直对齐,或使用悬挂缩进。 - 悬挂缩进
第一行不应该有参数,使用额外的缩进来清楚地将自己区分为延续行,或在悬挂缩进后空一行,来标识悬挂缩进结束。悬挂缩进可以通过非四个空格缩进 -
if
条件缩进
如if
条件过长,需要对条件进行换行缩进处理,可以在条件连接词处,增加一个空格,再增加圆括号创造一个时空个缩进的多行条件。
# 不添加额外缩进
if (this_is_one_thing and
that_is_another_thing):
do_something()
# 添加注释(便于看代码时区分)
if (this_is_one_thing and
that_is_another_thing):
# 当条件为真时
do_something()
# 在条件延续行上添加一些额外的缩进。
if (this_is_one_thing
and that_is_another_thing):
do_something()
- 多行结构上的右大括号/大括号/圆括号可以排列在列表最后一行的第一个非空格字符下,或者它可以排列在开始多行构造的行的第一个字符下面。
制表符 or 空格
- 空格是首选的缩进方式
- python3不允许混合使用制表符跟空格
- pycharm默认设置一个制表符等于四个空格
行的最大长度
- 所有行限制最大字符数为79
- 对于具有较少结构限制(文档字符串或注释)的长文本块,行长度应限制为72个字符。
- 对长行进行包装的首选方法是使用Python在圆括号、方括号和大括号中隐含的行延续。通过将表达式括在括号中,可以将长行分解为多行。这些应该优先使用,而不是使用反斜杠作为行延续。
- 反斜杠有时仍然是合适的。例如,long,多个with-statement不能使用隐式延续,所以反斜杠是可以接受的。
二元运算法与换行
- 优先使用Knuth的样式,即在运算符前进行换行(便于理解后续字段与前面字段做什么运算)
空行
- 用两行空行包围顶级函数和类定义。
- 类中的方法定义由一个空行包围。
- 可以使用额外的空白行来分隔相关函数组。一组相关的单行程序之间可以省略空行。
- 在函数中尽量使用空行来表示逻辑部分。
导入
- 导入不同库需要在分开的行
- 导入总是放在文件的顶部,在任何模块注释和文档字符串之后,在模块全局变量和常量之前。
- 导入顺序为
a. 标准库导入
b. 相关第三方库导入
c. 本地应用/特定于库导入
每一组导入之间加入空行 - 使用绝对导入,如果导入系统配置不正确,使用绝对路径会更加可读并且性能更好。但使用绝对路径导入不必要冗长的复杂包布局时,相对路径导入是一个可接受的替代方式。
- 当从包含类的模块导入类时,使用
from ... import...
- 避免使用通配符导入
from ... import *
,因为通配符导入使名称空间中出现的名称变得不清楚,从而混淆了阅读器和许多自动化工具。
字符串引号
- 对于一个引号的字符串,单引号字符串和双引号字符串是相同的。但需要使用同一规则,如果字符串包含单引号或双引号时,使用另一个字符串来避免字符串中的反斜杠。
- 对于三引号的字符串,始终使用双引号
表达式和语句中的空格
避免使用无关空格
下列情况不应该使用空格
- 紧跟在小括号,中括号或者大括号内
- 在逗号和紧跟其后的右括号之间
- 紧贴在逗号、分号或者冒号之前
- 在一个切片中,冒号的作用类似于一个二进制操作符,并且应该在每一边都具有相同的数量
- 在扩展的切片中,两个冒号的间距必须相同
- 紧接在开始函数调用的参数列表的左括号之前
- 紧接在开始索引或切片的开括号之前
- 赋值(或其他)运算符周围的多个空格,以使其与其他运算符对齐。
其他建议
- 避免在尾部添加空格
- 在二元运算符两边加一个空格
- 如果使用具有不同优先级的运算符,请考虑在具有最低优先级的运算符周围添加空格(最多为一个)
- 在制定关键字参数或者默认参数值的时候,不要在=附近加上空格
- 功能型注释应该使用冒号的一般性规则,并且在使用->的时候要在两边加空格
- 当给有类型备注的参数赋值的时候,在=两边添加空格(仅针对那种有类型备注和默认值的参数)
注释
基本要求
- 当代码更改时,始终优先保持注释是最新的
- 注释应该是完整的句子
- 块注释通常由一个或多个由完整句子组成的段落组成
- 在多句注释中,除最后一句外,在句末句号后应使用两个空格
块注释
- 块注释通常应用于它们后面的一些(或所有)代码,并且缩进到与代码相同的级别
- 块注释的每一行都以#和一个空格开始(除非注释内的文本是缩进的)
- 块注释中的段落由包含单个#的行分隔
行内注释
- 尽量少使用行内注释
- 行内注释是与语句位于同一行的注释
- 行内注释应该与语句至少分隔两个空格
- 行内注释应该以#和一个空格开始。
文档字符串
- 文档字符串对于非公共方法是不必要的,但是应该有一个注释来描述方法的功能
- 应该出现在
def
行之后 - 结束多行文档字符串的
"""
应该单独在一行上 - 对于一个一行文档字符串,请将结束符“”保持在同一行
命名规范
基本原则
- 露给用户的API接口的命名,应该遵循反映使用场景而不是实现的原则
命名风格
- 常见命名风格
a. b(单个小写字母)
b. B(单个大写字母)
c. lowercase 小写字母
d. lower_case_with_underscores 使用下划线分隔的小写字母
e. UPPERCASE 大写字母
f. UPPER_CASE_WITH_UNDERSCORES 使用下划线分隔的大写字母
g. CapitalizedWords(或者叫 CapWords,或者叫CamelCase 驼峰命名法 )
注意:当使用驼峰命名法时,所有缩写的字母用大写,(HTTPServerError 比 HttpServerError 好)
h. mixedCase(不同于首字母大写,第一个单词的首字母小写)
i. Capitalized_Words_With_Underscores(不建议使用)
j. 简短的惟一前缀与相关名称组合(python不常用) - 特殊的命名(通常和一些约定组合)
a._single_leading_underscore
: 弱“内部使用”指示符。
b.single_trailing_underscore_
: 被约定用来避免与Python关键字发生冲突
c.__double_leading_underscore
: 在命名类属性时,调用名称错误
d.__double_leading_and_trailing_underscore__
: 存在于用户控制的名称空间中的特殊(“magic”)对象或属性。
约定俗成:命名约定
避免使用的命名
- 不单独使用字符 'l'(小写的 'L') 已经 'I' (大写的 'i'),因为在某些字体制无法跟数字 1 区分
- 不单独使用 'O'(大写的 'o' ),在某些字体中无法与数字0区分
包和模块名称
- 模块名尽可能使用简短的、全小写的名称,如果下划线可以提高可读性,则可以在模块名称中使用下划线。
- 包也应该有短的、全小写的名称,尽管不鼓励使用下划线
- 当用C或c++编写的扩展模块有一个附带的Python模块,该模块提供了更高级别(例如更面向对象)的接口时,C/ c++模块有一个前边划线(例如_socket)。
类名
- 类名通常应该使用驼峰命名法约定
- 在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替
异常名
- 使用类命名方式,但需要在异常名后面加入“Error"
全局变量名
- 约定和函数命名规则一样
- 在全局变量前加下划线的方式(表明这些全局变量是模块内非公有)
函数名和变量名
- 函数名应该小写,如果想提高可读性可以用下划线分隔
- 变量名遵循与函数名相同的约定
- mixedCase只允许在已经是流行样式的上下文中使用(例如thread .py),以保持向后兼容性。
函数和方法参数
- 始终使用self作为实例方法的第一个参数
- 始终使用cls作为类方法的第一个参数
- 如果函数参数的名称与保留关键字发生冲突,通常最好在后面附加一个下划线,而不是使用缩写或拼写错误
方法名和实例变量
- 遵循这样的函数命名规则:使用下划线分隔小写单词以提高可读性。
- 在非共有方法和实例变量前使用单下划线。
- 通过双下划线前缀触发Python的命名转换规则来避免和子类的命名冲突。
- Python通过类名对这些命名进行转换:如果类
Foo
有一个叫__a
的成员变量, 它无法通过Foo.__a
访问。(执着的用户可以通过Foo._Foo__a
访问。)一般来说,前缀双下划线用来避免类中的属性命名与子类冲突的情况。
常量
- 常量通常在模块级定义,并使用所有大写字母和下划线分隔单词
继承设计
- 公共属性不应该有前缀下划线
- 如果公共属性名和关键字冲突,在属性名之后增加一个下划线
- 对于单一的共有属性数据,最好直接对外暴露它的变量名,而不是通过负责的 存取器(accessor)/突变(mutator) 方法。
- 如果你的类打算用来继承的话,并且这个类里有不希望子类使用的属性,就要考虑使用双下划线前缀并且没有后缀下划线的命名方式。
编程建议
- 代码应该用不损害其他Python实现的方式去编写
比如,不要依赖于在CPython中高效的内置字符连接语句 a += b 或者 a = a + b。这种优化甚至在CPython中都是脆弱的(它只适用于某些类型)并且没有出现在不使用引用计数的实现中。在性能要求比较高的库中,可以种 ”.join() 代替。这可以确保字符关联在不同的实现中都可以以线性时间发生。 - 和像None这样的单例对象进行比较的时候应该始终用 is 或者 is not,永远不要用等号运算符
- 使用 is not 运算符,而不是 not … is
- 当使用富比较实现排序操作的时候,最好实现全部的六个操作符(eq, ne, lt, gt, ge)而不是依靠其他的代码去实现特定的比较。
- 始终使用def表达式,而不是通过赋值语句将lambda表达式绑定到一个变量上
- 使用字符串方法代替字符串模块
- 使用 ”.startswith() 和 ”.endswith() 代替通过字符串切割的方法去检查前缀和后缀
- 对象类型的比较应该用isinstance()而不是直接比较type
- 对于序列来说(strings,lists,tuples),可以使用空序列为false的情况
- 书写字符串时不要依赖单词结尾的空格,这样的空格在视觉上难以区分,有些编辑器会自动去掉他们
- 不要用 == 去和True或者False比较