11 KiB
中国电信软件研发规范编码规范(Python 分册)
脱敏整理版:已移除编制人员、联系人和联系方式,并合并无意义硬换行。技术条款、章节和示例以原始 DOCX 为争议核验依据。
中国电信软件研发规范编码规范 (Python 分册) (修订版)
中国电信集团有限公司
2023 年 12 月
编制人员信息已移除。
版本变更历史
1 文档说明
1.1 编制说明
为了让不同编码习惯的开发者更好的协作配合, 并且形成良好的基础编码规范与风格, 提高代码安全性 、健壮性 、可读性, 本规范以 PEP8 为基础, 整理了工作中常见的不规范操作, 对 Python 项目开发编码过程进行规范化约束。
1.2 适用范围
本规范适用于指导中国电信软件研发工作。
1.3 起草单位
本规范的起草单位是中国电信集团公司。
1.4 解释权
本规范解释权属于中国电信集团公司。
1.5 版权
本规范的版权属于中国电信集团公司。
1.6 名词解释
PEP 8 约定了 Python 的推荐代码规范, 基于 Guido 和 Barry 的Python 代码风格规范改编而成。
2 Python 开发规范
2.1 命名规范
2.1.1 概述
-
【推荐】名字应该能够标识事物的特性, 并且与业务挂钩。
-
【推荐】名字应该使用英文单词, 而不能为拼音。
-
【推荐】名字可以有两个或三个单词组成, 但不应多于 4 个, 控制在 3至 30 个字母以内。
-
【强制】命名不能和关键字冲突。
2.1.2 包和模块命名
-
【强制】包命名采用全小写命名。
-
【推荐】通过功能命名。
-
【推荐】模块命名应短小, 并且全为小写, 如果需要多单词增加可读性,
使用下划线进行拼接。
2.1.3 类命名
-
【强制】类命名采用驼峰命名约定, 大写字母开头, 各个单词首字母大写。
-
【推荐】 当接口已文档化且主要是用作调用时, 也可以使用函数的命名风格约定。
2.1.4 函数命名
-
【推荐】 函数命名都是小写, 必要时使用下划线连接各单词提高可读性。
-
【推荐】只有当已有代码风格已经是混合大小写时, 为了保留向后兼容性才使用混合大小写。
-
【强制】用单下划线(_)开头表示模块函数是 protected 的。
-
【强制】用双下划线(__)开头的实例方法表示类内私有。
2.1.5 变量命名
-
【强制】变量名都是小写, 多单词使用下划线连接。
-
【推荐】类型变量名称通常应使用简短的驼峰命名, 建议将后缀_co 或_contra 添加到用于声明相应的协变和逆变的行为, 例
如:from typing import TypeVar
VT_co = TypeVar('VT_co', covariant=True)KT_contra = TypeVar('KT_contra', contravariant=True)
-
【强制】类型变量的定义统一放在 import 之后。
-
【强制】类变量统一放在类注释之后, 所有类函数之前。
-
【推荐】全局变量: 适用于函数的命名规范。
-
【强制】用单下划线(_)开头表示模块变量是 protected 的。
-
【强制】用双下划线(__)开头的实例变量表示类内私有。
2.1.6 常量命名
- 【推荐】全部使用大写并且下划线将单词分开。
2.1.7 异常命名
- 【推荐】 由于异常实际上也是类, 因此类命名的约定也适用与异常 。不同的是, 如果异常实际上是抛出错误的话, 异常名后应该加上“Error ”的后缀。
2.2 注释规范
2.2.1 概述
-
【推荐】一般情况下源程序的有效注释量必须在 30%以上。
-
【强制】避免使用装饰性内容, 保持注释的简洁。
-
【强制】注释信息不仅要包括代码的功能, 还应给出原因, 不要为注释而注释。
-
【强制】注释不能嵌套。
-
【强制】避免使用行尾注释。
-
【推荐】生成开发文档的需要用中文编写。
-
【推荐】如果需要注释的内容太多, 需附加文档进行说明, 注释时加上"参见《 ****》"。
-
【强制】复杂的分支流程必须注释。
-
【推荐】代码质量不高但能正常运行, 或者还没有实现的代码用# TODO:声明。
-
【参考】存在错误隐患的代码用# FIXME:声明。
2.2.2 程序文件注释
-
【强制】采用文档字符串的形式进行注释(三个双引号的形式) 。
-
【参考】应该包含如下:
文件描述 (Description): 描述此类的作用;# 作者 (Author): 创建者或者修改者名;# 版本 (Version): 创建或者修复时的编号, 需要自行在 bug 管理系统中创建 bug 号, 使用 bug 号进行命名(若无 bug 管理工具的临时办法: 如无 bug 号, 从 1 开始, 修改时依次增加);# 日期(Date): 创建或者修改时的日期, 使用“ - ”进行年月日分割;# 记录(Record): 创建或者修改的工作内容描述;
2.2.3 类注释
-
【强制】类应该在其定义下有一个用于描述该类的文档字符串。
-
【推荐】如果你的类有公共属性(Attributes), 那么文档中应该有一个属性(Attributes)段, 并且应该遵守和函数参数相同的格式。
2.2.4 函数和方法注释
下文所指的函数,包括函数 、方法 、 以及生成器。
- 【强制】一个函数必须要有文档字符串, 除非它满足以下条件之一:
a) 外部不可见
b) 非常短小
c) 简单明了
-
【强制】文档字符串应该包含函数做什么, 以及输入和输出的详细描述 。通常不应该描述“ 怎么做 ”, 除非是一些复杂的算法 。 当开发人员调用该函数时, 文档字符串应该提供足够的信息, 而无需看代码 。对于复杂的代码, 在代码旁边加注释会比使用文档字符串更有意义。
-
【参考】 关于函数的几个方面应该在特定的小节中进行描述记录, 这几个
方面如下文所述 。每节应该以一个标题行开始. 标题行以冒号结尾 。 除标题行外, 节的其他内容应被缩进 2 个空格。
- 【参考】Args:
列出每个参数的名字,并在名字后使用一个冒号和一个空格,分隔对该参数的描述 。如果描述太长超过了单行 80 字符,使用 2 或者 4 个空格的悬挂缩进(与文件其他部分保持一致) 。描述应该包括所需的类型和含义 。如果一个函数接受foo(可变长度参数列表)或者**bar (任意关键字参数),应该详细列出foo 和**bar。
- 【参考】Returns: (或者 Yields: 用于生成器)
描述返回值的类型和语义 。如果函数返回 None, 这一部分可以省略。
- 【参考】Raises:
列出与接口有关的所有异常。
2.2.5 块注释和行注释
-
【强制】块注释一般写在对应的代码之前, 并且和对应的代码有同样的缩进级别。
-
【强制】块注释的每一行都应该以#和一个空格开头(除非该文本是在注释内缩进对齐的) 。
-
【强制】块注释中的段落应该用只含单个#的一行隔开。
2.2.6 行内注释
-
【参考】尽量少用行内注释。
-
【参考】行内注释是和代码语句写在一行内的注释 。行内注释应该至少和代码语句之间有两个空格间隔, 并且以#和一个空格开始。
2.3 格式规范
2.3.1 概述
-
【强制】代码未写, 文档先行 。注释必须按照统一的范式编写。
-
【强制】 关系运算必须常量在左 、变量在右。
-
【强制】不许使用复杂的运算表达式, 必要时添加括号而不依赖于优先级。
2.3.2 缩进
-
【强制】缩进使用 4 个空格, 空格是首选的缩进方式。
-
【强制】禁止混用空格和 Tab。
2.3.3 换行
- 【推荐】每行代码的最大长度不该超过 80 个字符, 以下情况除外:
a) 长的导入模块语句
b) 注释里的 URL
2.3.4 空白行
-
【强制】使用 2 个空行来分隔最外层的函数(function)和类(class)定义。
-
【强制】使用 1 个空行来分隔类中的方法(method)定义。
-
【推荐】在函数内使用空行(尽量少) 使代码逻辑更清晰。
2.3.5 对齐
-
【强制】不要用空格来垂直对齐多行间的标记, 因为这会成为维护的负担(适用于:, #, =等)。
-
【推荐】续行应该与包裹元素对齐, 要么使用圆括号 、方括号 、花括号在
内的隐式行连接来垂直对齐, 要么使用悬挂行缩进对齐。垂直对齐:
2.3.6 库的导入
-
【强制】每个导入应该独占一行。
-
【强制】使用 import 开头的导入, 一行只能导入一个库, 禁止使用逗号分开导入多个库。
-
【推荐】使用from import 形式的导入, 一行只能导入一个库, 特殊情况下可以使用逗号分开导入多个库。
-
【强制】导入总应该放在文件顶部, 位于模块注释和文档字符串之后, 模块全局变量和常量之前 。导入应该按照从最通用到最不通用的顺序分组:
a) 标准库的导入
b) 第三方库的导入
c) 应用程序指定导入
-
【推荐】推荐使用绝对路径导入, 如果包导入时系统没有正确的配置(比如包里的一个目录在 sys.path 里的路径之后), 使用绝对路径会更具可读性(至少能提供错误信息):
-
【强制】 隐式相对 imports 是禁止使用的。
显示导入和隐式导入说明假设有如下包结构:
隐式相对导入, 是禁止使用的import bench# 显式相对导入
from . import bench
- 【推荐】显式的相对 imports 也是一种可以接受的方式, 标准库代码应当一直使用绝对 imports, 避免复杂的包布局。
from . import sibling from .sibling import example
2.3.7 字符串
- 【强制】避免在循环中用+和+=操作符来累加字符串。
主要原因:1. 字符串是不可变的, 每一次的赋值, 原来引用的对象没有及时被删除(系统有机制回收内存, 但是不及时), 增加内存负担;2. 随着字符串的累加, 长度越来越长, 写入的时间也逐渐增加, 所以如果循环规模比较大, 效率就明显下降。
- 【推荐】在同一个文件中, 保持使用字符串引号的一致性 。使用单引号 ’或者双引号"之一用以引用字符串, 并在同一文件中沿用。
2.3.8 空值比较
- 【推荐】使用 if foo is None: 形式来比较空值。
2.3.9 表达式和语句中的空格
- 【推荐】 以下情况避免无关的空格:
i. 在括号或大括号内
ii. 在尾随逗号和后面的右括号之间
iii. 在逗号, 分号或冒号前面正例:if x == 4: print x, y; x, y = y, x反例:if x == 4 : print x , y ; x , y = y , x
iv. 紧接在开始函数调用的参数列表的开括号之前正例:spam(1)反例:spam (1)
v. 紧接在索引或切片的左中括号之前
vi. 在一个赋值(或其他)运算符前后多于一个空格
- 【参考】其他建议
i. 总是围绕这些二元运算符在两侧使用一个空格正例:x = 1 y = 2 long_variable = 3反例:x = 1 y = 2 long_variable = 3
ii. 用于指示关键字参数或默认参数值时, 不要在=符号周围使用空格