📋 12. 代码质量与规范
💡 核心理念:优秀的代码不仅要能运行,更要易读、易维护、易扩展。代码质量是软件项目成功的基石。
✨ 12.1 代码风格与 PEP 8
📖 什么是 PEP 8?
PEP 8 是 Python 官方的代码风格指南,它定义了 Python 代码的编写规范,确保代码的一致性和可读性。
🎯 核心原则
📝 关键规范示例
✅ 好的代码风格
python
# 导入规范
import os
import sys
from flask import Flask, request, jsonify
# 类名使用驼峰命名
class UserManager:
"""用户管理类"""
def __init__(self, db_connection):
self.db = db_connection
# 方法名使用下划线
def create_user(self, username: str, email: str) -> dict:
"""创建新用户
Args:
username: 用户名
email: 邮箱地址
Returns:
包含用户信息的字典
"""
# 行长度不超过 79 字符
user_data = {
'username': username.strip().lower(),
'email': email.strip().lower(),
'created_at': datetime.utcnow()
}
return user_data1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
❌ 不好的代码风格
python
# 导入混乱
from flask import *
import os,sys
# 命名不规范
class userManager:
def __init__(self,db):
self.db=db
def createUser(self,username,email):
userData={'username':username.strip().lower(),'email':email.strip().lower(),'created_at':datetime.utcnow()}
return userData1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🛠️ 自动化工具
配置示例
toml
# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py38']
[tool.isort]
profile = "black"
multi_line_output = 3
[tool.flake8]
max-line-length = 88
extend-ignore = E203, W5031
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
🔍 12.2 类型注解与静态分析
💭 为什么需要类型注解?
类型注解让代码更加清晰,帮助 IDE 提供更好的代码补全,并能在运行前发现潜在错误。
📊 类型注解的演进
🎯 Flask 应用中的类型注解
python
from typing import Dict, List, Optional, Union
from flask import Flask, Request, Response
from dataclasses import dataclass
@dataclass
class User:
"""用户数据模型"""
id: int
username: str
email: str
is_active: bool = True
roles: List[str] = None
def __post_init__(self):
if self.roles is None:
self.roles = ['user']
class UserService:
"""用户服务类"""
def __init__(self, db_session) -> None:
self.db = db_session
def get_user(self, user_id: int) -> Optional[User]:
"""根据ID获取用户"""
user_data = self.db.query(User).filter_by(id=user_id).first()
return user_data
def create_user(self, user_data: Dict[str, Union[str, bool]]) -> User:
"""创建新用户"""
user = User(
id=0, # 数据库自动生成
username=user_data['username'],
email=user_data['email'],
is_active=user_data.get('is_active', True)
)
return user
# Flask 路由的类型注解
from flask import jsonify
def create_user_endpoint() -> Response:
"""创建用户的 API 端点"""
user_service = UserService(db.session)
user_data = request.get_json()
try:
new_user = user_service.create_user(user_data)
return jsonify({
'success': True,
'user': {
'id': new_user.id,
'username': new_user.username,
'email': new_user.email
}
}), 201
except Exception as e:
return jsonify({'error': str(e)}), 4001
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
🔧 MyPy 静态类型检查
bash
# 安装 mypy
pip install mypy
# 检查类型
mypy app.py1
2
3
4
5
2
3
4
5
配置文件 mypy.ini:
ini
[mypy]
python_version = 3.8
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
[mypy-flask.*]
ignore_missing_imports = True1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
👥 12.3 代码审查流程
🔄 代码审查的价值循环
📋 审查检查清单
🎯 功能性检查
- [ ] 代码是否实现了预期功能?
- [ ] 边界条件是否处理正确?
- [ ] 错误处理是否完善?
- [ ] 性能是否满足要求?
🏗️ 架构与设计
- [ ] 代码结构是否清晰?
- [ ] 是否遵循 SOLID 原则?
- [ ] 是否有代码重复?
- [ ] 接口设计是否合理?
📖 可读性与维护性
- [ ] 变量和函数命名是否清晰?
- [ ] 注释是否充分且准确?
- [ ] 代码逻辑是否易于理解?
🛠️ 实践示例
python
# 审查前的代码
def process_data(data):
result = []
for item in data:
if item['status'] == 'active':
result.append(item['value'] * 2)
return result
# 审查后的改进代码
from typing import List, Dict, Any
def calculate_active_values(items: List[Dict[str, Any]],
multiplier: float = 2.0) -> List[float]:
"""计算活跃项目的值
Args:
items: 包含状态和值的项目列表
multiplier: 乘数因子
Returns:
计算后的值列表
Raises:
KeyError: 当项目缺少必要字段时
TypeError: 当值不能进行数学运算时
"""
try:
return [
float(item['value']) * multiplier
for item in items
if item.get('status') == 'active'
]
except (KeyError, TypeError, ValueError) as e:
raise ValueError(f"数据处理失败: {e}")1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
🔄 12.4 重构技巧与实践
🎯 重构的时机
🚨 常见代码异味
1. 长方法 (Long Method)
python
# ❌ 重构前:方法过长
def process_user_registration(user_data):
# 验证数据(20行代码)
if not user_data.get('email'):
raise ValueError('邮箱不能为空')
# ... 更多验证逻辑
# 创建用户(15行代码)
user = User()
user.email = user_data['email']
# ... 更多创建逻辑
# 发送邮件(10行代码)
email_service = EmailService()
# ... 邮件发送逻辑
return user
# ✅ 重构后:职责分离
class UserRegistrationService:
def __init__(self, email_service: EmailService):
self.email_service = email_service
def register_user(self, user_data: Dict[str, Any]) -> User:
"""用户注册主流程"""
self._validate_user_data(user_data)
user = self._create_user(user_data)
self._send_welcome_email(user)
return user
def _validate_user_data(self, user_data: Dict[str, Any]) -> None:
"""验证用户数据"""
if not user_data.get('email'):
raise ValueError('邮箱不能为空')
# 其他验证逻辑
def _create_user(self, user_data: Dict[str, Any]) -> User:
"""创建用户对象"""
return User(
email=user_data['email'],
username=user_data['username']
)
def _send_welcome_email(self, user: User) -> None:
"""发送欢迎邮件"""
self.email_service.send_welcome_email(user.email)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2. 重复代码 (Duplicate Code)
python
# ❌ 重构前:代码重复
class UserController:
def get_user(self, user_id):
if not user_id:
return {'error': '用户ID不能为空'}, 400
if not isinstance(user_id, int):
return {'error': '用户ID必须是整数'}, 400
# 获取用户逻辑
def update_user(self, user_id, data):
if not user_id:
return {'error': '用户ID不能为空'}, 400
if not isinstance(user_id, int):
return {'error': '用户ID必须是整数'}, 400
# 更新用户逻辑
# ✅ 重构后:提取公共方法
class UserController:
def _validate_user_id(self, user_id: Any) -> Optional[Tuple[Dict, int]]:
"""验证用户ID"""
if not user_id:
return {'error': '用户ID不能为空'}, 400
if not isinstance(user_id, int):
return {'error': '用户ID必须是整数'}, 400
return None
def get_user(self, user_id: int):
error_response = self._validate_user_id(user_id)
if error_response:
return error_response
# 获取用户逻辑
def update_user(self, user_id: int, data: Dict):
error_response = self._validate_user_id(user_id)
if error_response:
return error_response
# 更新用户逻辑1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
🔧 重构工具与技巧
📚 12.5 文档编写规范
📖 文档层次结构
🎯 Python 文档字符串规范
python
def calculate_user_score(user_id: int,
score_type: str = 'overall',
include_bonus: bool = True) -> Dict[str, Union[int, float]]:
"""计算用户评分
根据用户的活动数据计算综合评分,支持多种评分类型。
Args:
user_id: 用户唯一标识符
score_type: 评分类型,可选值:
- 'overall': 综合评分(默认)
- 'activity': 活跃度评分
- 'quality': 质量评分
include_bonus: 是否包含奖励分数
Returns:
包含评分信息的字典:
{
'user_id': int,
'score': float,
'score_type': str,
'calculated_at': str
}
Raises:
ValueError: 当 user_id 无效或 score_type 不支持时
DatabaseError: 当数据库查询失败时
Example:
>>> calculate_user_score(123, 'overall', True)
{
'user_id': 123,
'score': 85.5,
'score_type': 'overall',
'calculated_at': '2024-01-15T10:30:00Z'
}
Note:
评分计算基于过去30天的用户活动数据。
奖励分数仅在用户等级大于等于3时生效。
"""
# 实现逻辑...
pass1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
📋 README 文档模板
markdown
# 项目名称 🚀
> 简短的项目描述
[]
[]
[]
## ✨ 特性
- 🎯 核心功能1
- 🔧 核心功能2
- 📊 核心功能3
## 🚀 快速开始
### 环境要求
- Python 3.8+
- Flask 2.0+
- PostgreSQL 12+
### 安装
```bash
# 克隆项目
git clone https://github.com/username/project.git
cd project
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# 安装依赖
pip install -r requirements.txt1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
配置
bash
# 复制配置文件
cp .env.example .env
# 编辑配置
vim .env1
2
3
4
5
2
3
4
5
运行
bash
# 数据库迁移
flask db upgrade
# 启动开发服务器
flask run1
2
3
4
5
2
3
4
5
📖 API 文档
详细的 API 文档请访问:[API Documentation]
🧪 测试
bash
# 运行所有测试
pytest
# 运行特定测试
pytest tests/test_user.py
# 生成覆盖率报告
pytest --cov=app tests/1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🤝 贡献
- Fork 项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 打开 Pull Request
📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE] 文件了解详情。
🔄 12.6 持续集成/持续部署(CI/CD)
🎯 CI/CD 流水线设计
🔧 GitHub Actions 配置
yaml
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: Lint with flake8
run: |
flake8 app tests --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 app tests --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics
- name: Format check with black
run: black --check app tests
- name: Type check with mypy
run: mypy app
- name: Security check with bandit
run: bandit -r app
- name: Test with pytest
env:
DATABASE_URL: postgresql://postgres:postgres@localhost/test_db
run: |
pytest tests/ -v --cov=app --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Deploy to production
run: |
echo "部署到生产环境"
# 实际的部署脚本1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
🐳 Docker 集成
dockerfile
# Dockerfile
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非 root 用户
RUN useradd --create-home --shell /bin/bash app \
&& chown -R app:app /app
USER app
# 暴露端口
EXPOSE 5000
# 健康检查
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
# 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:create_app()"]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
📊 质量门禁配置
yaml
# .github/workflows/quality-gate.yml
name: Quality Gate
on:
pull_request:
branches: [ main ]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: 3.9
- name: Install dependencies
run: |
pip install -r requirements-dev.txt
- name: Run quality checks
run: |
# 代码覆盖率必须 >= 80%
pytest --cov=app --cov-fail-under=80
# 代码复杂度检查
radon cc app --min B
# 安全漏洞扫描
safety check
# 依赖许可证检查
pip-licenses --fail-on 'GPL'
- name: Comment PR
uses: actions/github-script@v6
if: failure()
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ 质量门禁检查失败,请修复后重新提交。'
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
🎯 最佳实践总结
🎯 本章小结
通过本章的学习,你应该掌握了:
- ✅ PEP 8 规范:编写符合 Python 官方标准的代码
- ✅ 类型注解:提高代码可读性和IDE支持
- ✅ 代码审查:建立有效的团队协作流程
- ✅ 重构技巧:识别和改进代码异味
- ✅ 文档规范:编写清晰的技术文档
- ✅ CI/CD 流程:自动化代码质量保证
💡 记住:优秀的代码质量不是一蹴而就的,需要团队持续的努力和改进。从小处做起,逐步建立完善的质量保证体系。
下一章预告 📖:我们将学习如何设计和实现全面的测试策略,确保应用的稳定性和可靠性。
