QMK固件项目Python编码规范详解
前言
在QMK固件项目中,Python代码主要用于构建和测试工具链。为了保持代码的一致性和可维护性,项目制定了一套基于PEP8但有所调整的Python编码规范。本文将深入解析这些规范,帮助开发者编写符合项目要求的Python代码。
基础规范
版本与兼容性
项目明确要求使用Python 3.9版本,以确保在所有支持平台上都能正常运行。这是考虑到不同操作系统可能预装的Python版本差异而做出的决定。
代码缩进
采用4个空格作为缩进标准,这与PEP8规范一致。注意不要使用制表符(Tab),而是使用软制表符(空格)。
注释规范
注释在项目中扮演着重要角色:
- 应将注释视为描述功能的故事
- 重点解释"为什么"做出某些决策,而不仅仅是"做什么"
- 避免显而易见的注释
- 当不确定注释是否必要时,倾向于添加注释
文档字符串
所有函数都必须包含有用的文档字符串(docstring),这是项目强制要求。文档字符串应清晰描述函数的功能和使用方法。
行长限制
项目对代码行长度持宽松态度:
- 原则上不强制换行
- 如需换行,建议不超过76个字符
- 这种宽松政策是为了提高代码可读性
代码格式化工具
项目推荐使用yapf作为代码格式化工具,并提供了专门的配置文件。yapf可以根据项目规范自动调整代码格式,确保风格统一。
导入规范
导入方式选择
项目没有严格的导入规则,但提供了以下指导原则:
- 优先从模块导入特定函数和类名,使代码更简洁
- 当导入可能导致名称冲突时,导入整个模块
- 避免使用"as"关键字重命名导入,除非导入兼容性模块
- 每个模块导入单独一行
导入分组
导入语句应按以下顺序分组:
- 系统模块
- 第三方模块
- 本地模块
禁止的导入方式
明确禁止使用from foo import *
这种通配符导入方式,应明确列出需要导入的对象。
导入示例分析
文章提供了多个导入示例,展示了良好和不良的导入实践。关键点是保持代码清晰可读,避免引起混淆。
命名规范
项目采用以下命名约定:
module_name
:模块名小写,下划线分隔package_name
:包名小写,下划线分隔ClassName
:类名首字母大写method_name
:方法名小写,下划线分隔function_name
:函数名小写,下划线分隔GLOBAL_CONSTANT_NAME
:全局常量全大写global_var_name
:全局变量小写instance_var_name
:实例变量小写function_parameter_name
:函数参数小写local_var_name
:局部变量小写
命名注意事项
- 名称应具有描述性,避免缩写
- 特别避免使用项目外部人员可能不熟悉的缩写
- 文件名应使用.py扩展名,避免使用连字符
应避免的命名
- 除计数器或迭代器外,避免单字符名称
- 避免在模块/包名中使用连字符(-)
- 避免使用双下划线开头和结尾的名称(如
__init__
)
文档字符串规范
基本格式要求
- 使用Markdown格式
- 使用三重引号,并至少包含一个换行符
- 第一行是简短描述(不超过70字符)
- 如需详细说明,在简短描述后空一行
- 缩进的行应与开头引号保持相同缩进
内容结构
文档字符串应包含以下部分(如适用):
- 函数简短描述
- 详细说明(可选)
- Args: 参数说明
- Returns: 返回值说明
- Raises: 可能抛出的异常
各部分之间用空行分隔。
文档字符串示例
文章提供了简单、复杂和带参数说明的三种文档字符串示例,展示了不同情况下的最佳实践。
异常处理规范
- 异常应仅用于处理异常情况,而非流程控制
- 捕获异常时应处理真正异常的情况
- 如使用catch-all异常,必须记录异常和堆栈跟踪
- 保持try/except块尽可能短小
- 如需大量try语句,应考虑重构代码
数据结构规范
元组
定义单元素元组时必须包含尾随逗号,以明确表示这是元组而非表达式。避免依赖隐式的单元素元组解包。
列表和字典
项目配置了yapf以不同方式处理带尾随逗号的序列:
- 无尾随逗号:格式化为单行
- 有尾随逗号:每个元素单独一行
建议短定义保持单行,较长的定义应换行以提高可读性。
其他语法规范
括号使用
避免过度使用括号,但可用括号提高代码可读性。return语句中除非显式返回元组或数学表达式,否则避免使用括号。
字符串格式化
推荐使用printf风格(%操作符)的字符串格式化,这与项目广泛使用的日志模块保持一致,也更符合C程序员的习惯。
推导式与生成器
鼓励使用列表推导式和生成器表达式,但避免过于复杂的表达式。复杂情况下应使用常规for循环。
Lambda函数
允许使用但不鼓励,因为推导式和生成器已能覆盖大多数使用场景。
条件表达式
允许在变量赋值中使用,但应避免在其他场景(如函数参数、序列元素等)中使用,因其可读性较差。
默认参数值
鼓励使用默认参数,但值必须是不可变对象。使用可变对象作为默认值会导致修改在调用间持续,通常不是预期行为。
面向对象规范
属性访问
始终使用@property装饰器而非getter/setter方法。这提供了更Pythonic的接口。
真值判断
在if语句中应优先使用隐式的真值判断,而非显式的True/False比较。
装饰器
在适当场景下使用装饰器,但避免过多"魔法"代码,除非能显著提高可读性。
高级特性限制
项目明确限制使用以下高级特性:
- 线程和多进程:通常应避免,如需使用需充分论证
- Python高级特性:如自定义元类、字节码访问、动态编译、动态继承等
- 类型注解:目前项目不使用任何类型注解系统
这些限制是为了保持代码对非Python专家的可读性和可理解性。
函数设计规范
函数长度
推荐编写小而专注的函数。虽然没有严格限制,但建议:
- 超过约40行时应考虑拆分
- 长函数可能隐藏复杂逻辑,增加维护难度
- 遇到复杂的长函数时,应勇敢重构
代码标记规范
FIXME注释
允许在代码中留下FIXME注释,格式为:
FIXME(用户名): 当某功能完成时重新审视此代码
这种注释有助于标记需要进一步思考或重构的代码区域。
测试规范
项目采用集成测试和单元测试相结合的方式确保代码质量。
集成测试
位于test_cli_commands.py
中,通过subprocess运行CLI命令并验证整体行为,检查输出和返回码。
单元测试
其他测试文件包含针对各个模块的单元测试。测试文件命名应与模块名对应(点替换为下划线)。
目前测试套件尚未使用模拟(mocking)技术,欢迎贡献改进。
结语
QMK固件项目的Python编码规范在PEP8基础上进行了适当调整,主要目标是提高代码对非Python专家的可读性。理解并遵循这些规范将有助于开发者贡献高质量的代码,同时保持项目代码风格的一致性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考