7.6 KiB
Python 编码与开发规范
Python 是一门极其灵活的动态语言,但“灵活”在大型团队协作中往往意味着“灾难”。本规范以 PEP 8 为基石,全面拥抱 现代 Python (3.9+) 的类型注解系统,并强制依赖自动化工具链来消除代码风格争议。
命名约定与基础风格
核心理念:代码是写给人看的,顺便交给机器执行。
-
变量与函数(变量/方法): 强制使用 snake_case(下划线命名)。
# 推荐
user_account_list = []def fetch_user_data():
... -
类名(Classes): 强制使用 PascalCase(大驼峰命名)。
class PaymentService:
...class UserNotFoundError(Exception):
... -
常量(Constants): 强制使用 SCREAMING_SNAKE_CASE(全大写加下划线),定义在模块顶部。
-
布尔语义命名: 布尔变量与布尔返回值应使用
is_、has_、can_、allow_前缀,避免语义歧义。 -
集合语义命名: 列表、集合、查询结果变量应使用复数命名(如
users,orders,permission_codes)。 -
私有与受保护属性: * 单下划线 _private_var:表示内部使用(软性约束,仅作提示)。
- 双下划线 __strict_private:触发名称改写(Name Mangling),除非极特殊情况(如防止子类重写),日常业务开发中不推荐使用,以免增加调试难度。
现代工程化工具链 (强制执行)
核心理念:能用工具自动修复的风格问题,绝不在 Code Review 中浪费时间口舌。
项目中必须配置并使用以下工具链(推荐通过 pre-commit 钩子强制拦截不合规代码):
- 项目与依赖管理:uv (核心基石)
- 摒弃传统的 pip、virtualenv 或臃肿的 Poetry,全面拥抱由 Astral 团队用 Rust 编写的 uv。
- 它统一了虚拟环境管理、依赖解析和项目运行。使用 uv init 初始化项目,uv add 添加依赖,uv run 执行脚本,极大提升开发构建体验。
- 综合 Linter 与格式化:Ruff
- 同样是 Astral 团队出品的极速工具,完美兼容并替代了 Flake8、isort 和 Black(Ruff 目前已内置极速 formatter)。团队统一在 pyproject.toml 中配置 Ruff 规则。
- 静态类型检查:Mypy
- 开启严格模式。核心业务模块必须通过 Mypy 检查,不允许出现 Any 泛滥的情况。
类型注解 (Type Hinting) 规范
核心理念:动态一时爽,重构火葬场。所有业务接口、函数签名必须带有完整的类型注解。
-
基础类型约束: 充分利用 Python 3.9+ 的内置泛型(如 list, dict,不再需要 from typing import List, Dict)和 Python 3.10+ 的联合类型操作符 |。
# 推荐写法 (Python 3.10+)
def process_user_data(user_id: int | str, tags: list[str]) -> dict[str, Any]:
pass -
可选类型: 当参数或返回值可能为空时,必须使用 Optional[T] 或 T | None。
def find_user(email: str) -> User | None:
pass -
避免 Any 滥用: 凡是写 Any 的地方,意味着放弃了类型检查。对于复杂的数据结构,应当优先定义 TypedDict 或数据模型类。
核心编码与设计范式
1. 数据模型设计 (Pydantic 与 Dataclass 的明确边界)
警惕过度设计: 绝对不要为了用而用,将整个系统“全盘 Pydantic 化”。Pydantic 实例化时的类型强转和校验是有显著性能开销的,强行铺满内部逻辑会带来极大的工作量和性能负担。
- 必须使用 Pydantic 的场景(防腐层/系统边界):
- 外部 API 的请求体与响应体验证(如 FastAPI 集成)。
- 外部配置文件的解析加载。
- 从不可靠来源(如第三方消息队列)消费的复杂 JSON 结构。
from pydantic import BaseModel, EmailStr
class UserCreateRequest(BaseModel):
name: str
email: EmailStr # 外部输入,必须靠 Pydantic 严防死守
age: int | None = None
- 必须使用 @dataclass 或 TypedDict 的场景(系统内部):
- 内部 Service 函数之间的参数流转。
- 从数据库 ORM 查询出来、组装准备传给下一层的纯内部 DTO。
- 这些数据已经是“绝对可信”的,使用标准库的 @dataclass 可以实现近乎 O(1) 的轻量实例化,绝不增加无谓的校验负担。
2. 函数参数设计 (关键字传参)
-
当函数参数超过 3 个,或者包含容易混淆的布尔值时,强制使用 * 迫使调用方使用关键字传参。
# 规范示例:调用此函数时,age 和 is_active 必须带上参数名
def create_user(name: str, email: str, *, age: int, is_active: bool = True) -> User:
pass# 调用端:
create_user("John", "john@test.com", age=25, is_active=False) # 必须写明 age= 和 is_active=
3. 异常处理规约
- 禁止吞噬异常: 绝不允许出现 except Exception: pass 这种掩耳盗铃的代码。
- 自定义异常层次: 模块应当抛出特定业务领域的异常(如继承自 ValueError 的 OrderNotFoundError),而不是直接抛出裸露的 Exception。
- 边界层错误策略: 在 API、CLI、任务入口等边界层,应优先“抛异常并交由统一处理”,避免在底层函数中拼接错误响应字符串。
4. 资源释放与安全
- 强制使用上下文管理器: 文件读写、网络会话(如 requests.Session)、数据库连接,必须使用 with 语句包裹,确保资源(哪怕在异常抛出时)能被正确关闭。
性能优化与防坑指南
Python 性能上限不高,但不良写法会导致下限极低:
- 查找操作慎用 List,拥抱 Set/Dict:
- if item in my_list: 的时间复杂度是 O(n)。对于包含上百个元素的成员判断,必须将集合初始化为 Set 或 Dict,以达到 O(1) 的查找性能。
- 大数据流拥抱生成器 (Generators):
- 当处理百万级行数的 CSV 或大量数据库记录时,严禁将数据一次性加载到内存的 List 中。必须使用 yield。
def process_large_file(filename: str):
with open(filename, 'r') as file:
for line in file:
yield process_line(line) # 内存中始终只有一行数据
- 海量实例的内存优化:
- 当需要实例化上百万个轻量级对象时,必须在类中声明 __slots__ = ['attr1', 'attr2'],这能节约约 40% 的内存消耗(阻止 Python 为每个实例创建 __dict__)。
单元测试规范
-
测试框架选型: 统一使用 pytest,废弃 Python 自带的厚重 unittest 类式写法。并通过 uv run pytest 执行。
-
测试用例结构: 遵循 Arrange - Act - Assert (准备-执行-断言) 三段式结构。
-
Mock 的边界: 严禁在单元测试中发起真实的 HTTP 网络请求或连接真实的 MySQL 数据库。必须使用 unittest.mock.patch 或 pytest-mock 对外部 IO 依赖进行拦截和模拟。
def test_get_user_info(mocker):
# Arrange: 拦截外部数据库调用
mocker.patch('myproject.database.fetch', return_value={"id": 1, "name": "Test"})\# Act user \= get\_user\_info(1) \# Assert assert user.name \== "Test"
🤖 [附加] AI 助手执行协议 (AI Output Schema)
绝对红线:生成的 Python 代码必须 100% 包含 Type Hints(类型注解);禁止输出废话解析,直接输出带规范中文注释的可用代码块。