Python自动化脚本代码质量检查完全指南
·
代码写多了,难免有些"代码债"。变量命名不规范、代码格式乱七八糟、潜在bug没发现……这些问题日积月累会让代码越来越难维护。代码质量检查工具能帮我们自动化地发现问题、保持代码整洁。
一、为什么要做代码质量检查
- 发现问题:静态检查能发现潜在bug
- 统一风格:团队代码风格一致
- 提高可读性:规范的代码更容易理解
- 减少review负担:工具能发现的不用人肉找
二、基础工具:Flake8
Flake8是最常用的Python代码检查工具,集合了pyflakes、pycodestyle、mccabe。
# 安装
pip install flake8
# 基本使用
flake8 your_script.py
# 检查整个项目
flake8 .
# 忽略特定规则
flake8 --ignore=E501,W503 your_script.py
# 输出详细格式
flake8 --show-source --statistics your_script.py
配置.flake8文件:
[flake8]
max-line-length = 120
exclude =
.git,
__pycache__,
build,
dist,
*.egg-info
ignore =
E203, # whitespace before ':'
W503, # line break before binary operator
per-file-ignores =
__init__.py:F401,F403
max-complexity = 10
三、格式化工具:Black
Black是"固执己见"的格式化工具,它决定了代码风格,你不用操心。
# 安装
pip install black
# 格式化单个文件
black your_script.py
# 格式化整个项目
black .
# 检查是否需要格式化(不实际修改)
black --check your_script.py
# 查看会做什么改动
black --diff your_script.py
配合pre-commit使用:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
language_version: python3
四、导入排序:isort
统一import语句的顺序。
# 安装
pip install isort
# 检查import顺序
isort --check-only your_script.py
# 自动排序
isort your_script.py
# 与black配合
isort --profile black your_script.py
配置pyproject.toml:
[tool.isort]
profile = "black"
line_length = 120
skip_gitignore = true
五、类型检查:mypy
Python动态类型虽灵活,但也容易出错。mypy帮你做静态类型检查。
# 示例:有类型注解的代码
def process_data(data: list[dict]) -> dict:
result = {}
for item in data:
key = item.get('id')
value = item.get('value', 0)
if key:
result[key] = value
return result
# 安装
pip install mypy
# 运行检查
mypy your_script.py
# 严格模式
mypy --strict your_script.py
# 忽略缺失的类型
mypy --ignore-missing-imports your_script.py
六、综合工具:pylint
pylint是最全面的代码检查工具,检查项非常多。
# 安装
pip install pylint
# 检查
pylint your_script.py
# 输出评估分数
pylint --output-format=text your_script.py | tail -5
# 生成报告
pylint --reports=y your_script.py
配置.pylintrc:
[MESSAGES CONTROL]
disable=C0111, # missing-docstring
C0103 # invalid-name
[FORMAT]
max-line-length=120
[DESIGN]
max-args=8
max-locals=20
七、自动化检查脚本
写一个一键检查脚本:
#!/usr/bin/env python3
"""
代码质量检查脚本
"""
import subprocess
import sys
from pathlib import Path
from dataclasses import dataclass
@dataclass
class CheckResult:
tool: str
passed: bool
message: str = ""
class CodeQualityChecker:
def __init__(self, target='.'):
self.target = Path(target)
self.results = []
def run_command(self, cmd, description):
"""运行命令并返回结果"""
try:
result = subprocess.run(
cmd, shell=True, capture_output=True, text=True
)
passed = result.returncode == 0
message = result.stdout.strip() if result.stdout else result.stderr.strip()
return CheckResult(description, passed, message)
except Exception as e:
return CheckResult(description, False, str(e))
def check_flake8(self):
"""Flake8检查"""
result = self.run_command(
f'flake8 {self.target} --max-line-length=120 --extend-ignore=E203,W503',
"Flake8"
)
if result.passed:
result.message = "✓ 检查通过"
else:
# 只显示错误摘要
lines = result.message.split('\n')[:10] # 只显示前10条
result.message = '\n'.join(lines)
return result
def check_black(self):
"""Black格式检查"""
result = self.run_command(
f'black --check {self.target}',
"Black"
)
if result.passed:
result.message = "✓ 格式正确"
else:
result.message = "需要格式化"
return result
def check_isort(self):
"""isort导入排序检查"""
result = self.run_command(
f'isort --check-only --diff {self.target}',
"isort"
)
if result.passed:
result.message = "✓ 导入顺序正确"
else:
result.message = "导入需要排序"
return result
def check_mypy(self):
"""mypy类型检查"""
py_files = list(self.target.rglob('*.py'))
if not py_files:
return CheckResult("mypy", True, "无Python文件")
py_files_str = ' '.join(str(f) for f in py_files)
result = self.run_command(
f'mypy {py_files_str} --ignore-missing-imports',
"mypy"
)
if result.passed:
result.message = "✓ 类型检查通过"
return result
def check_pylint(self):
"""pylint检查(只检查主要模块)"""
main_files = list(self.target.glob('*.py'))
if not main_files:
return CheckResult("pylint", True, "无主文件")
for f in main_files:
if f.name not in ['setup.py', '__main__.py']:
result = self.run_command(
f'pylint --disable=C,R {f}',
"pylint"
)
# pylint分数10分满分,太严格了,改成警告
if not result.passed and 'error' in result.message.lower():
return result
return CheckResult("pylint", True, "✓ 检查通过")
def auto_fix(self):
"""自动修复可修复的问题"""
print("执行自动修复...\n")
# isort
print("1. 排序导入...")
subprocess.run(f'isort {self.target}', shell=True)
# black
print("2. 格式化代码...")
subprocess.run(f'black {self.target}', shell=True)
print("\n自动修复完成!")
def run_all(self):
"""运行所有检查"""
checks = [
self.check_flake8,
self.check_black,
self.check_isort,
self.check_mypy,
]
print("=" * 60)
print("开始代码质量检查")
print("=" * 60 + "\n")
all_passed = True
for check in checks:
result = check()
self.results.append(result)
status = "✓ PASS" if result.passed else "✗ FAIL"
print(f"{status} | {result.tool}")
if result.message:
print(f" {result.message}")
if not result.passed:
all_passed = False
print()
print("=" * 60)
if all_passed:
print("✓ 所有检查通过!")
else:
failed = [r.tool for r in self.results if not r.passed]
print(f"✗ 以下检查未通过: {', '.join(failed)}")
print("\n可以尝试自动修复: python quality_check.py --fix")
print("=" * 60)
return all_passed
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--target', default='.', help='检查目标目录')
parser.add_argument('--fix', action='store_true', help='自动修复')
args = parser.parse_args()
checker = CodeQualityChecker(args.target)
if args.fix:
checker.auto_fix()
else:
success = checker.run_all()
sys.exit(0 if success else 1)
八、Git钩子:pre-commit
配置Git钩子,提交前自动检查:
# 安装pre-commit
pip install pre-commit
# 创建配置
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: ['--profile', 'black']
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
args: ['--max-line-length=120', '--extend-ignore=E203,W503']
# 安装钩子
pre-commit install
# 手动运行
pre-commit run --all-files
九、CI/CD集成
GitHub Actions中集成检查:
# .github/workflows/quality.yml
name: Code Quality
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install tools
run: |
pip install flake8 black isort mypy
pip install -e .
- name: Run quality checks
run: |
flake8 . --max-line-length=120 --extend-ignore=E203,W503
black --check .
isort --check-only --profile black .
mypy . --ignore-missing-imports
总结
代码质量工具推荐组合:
| 工具 | 用途 | 必要性 |
|---|---|---|
| Black | 代码格式化 | 必装 |
| isort | 导入排序 | 必装 |
| Flake8 | 基础检查 | 必装 |
| mypy | 类型检查 | 推荐 |
| pre-commit | Git钩子 | 推荐 |
| pylint | 深度检查 | 可选 |
建议:
- 新项目:从一开始就配置好这些工具
- 老项目:逐步添加检查,先忽略已有问题
- 团队:统一配置,提交前必须通过检查
- CI/CD:把检查集成到流水线中
好的工具配合好的习惯,代码质量想不好都难。
更多推荐
所有评论(0)