关于 py-complexity
py-complexity 是面向 Python 开发者的代码复杂度测量与降低技能。它指导重构和趋势跟踪,并可在 CI/CD 中执行阈值检查。
主要功能
- 01测量圈复杂度与认知复杂度
- 02查找复杂函数和过长文件
- 03应用代码重构模式
- 04跟踪 Git 历史中的复杂度趋势
- 05在 CI/CD 中执行阈值检查
适用场景
- 01识别需要重构的 Python 代码
- 02减少嵌套与重复逻辑
- 03在开发过程中监控复杂度变化
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ l-mb/ python-refactoring-skills --skill py-complexity安装后在 Claude Code 中输入/py-complexity确认已加载。
详细介绍
Python 复杂度降低
降低代码复杂度,提升可维护性和可理解性。
有效利用上下文窗口。
目标
- 衡量圈复杂度和认知复杂度
- 找出过于复杂的函数和模块
- 找出过长的文件(代码文件不超过 500 行,除非无法避免)
- 应用重构模式以降低复杂度
- 持续跟踪复杂度改进情况
- 在 CI/CD 中强制执行复杂度阈值
必需工具
添加到 [dependency-groups] dev:"radon"、"lizard"、"xenon"、"wily"
- radon:圈复杂度和可维护性指数
- lizard:认知复杂度(更有利于提升可读性)
- xenon:强制执行 CI/CD 阈值
- wily:跟踪 git 历史中的趋势
权限:先运行 py-quality-setup,以配置 .claude/settings.local.json,添加所有必需的工具权限。
发现阶段
衡量复杂度
# Key commands
radon cc . -n C # Functions with complexity ≥11
lizard -C 15 . # Cognitive complexity warnings
radon mi . -n B # Maintainability index <65
wily build . # Initialize tracking (one-time)
wily diff HEAD~10 # Compare trends
scc --by-file --ci # Optional: code statistics (called 'sccount' on openSUSE)
阈值
- 圈复杂度:达到 ≥C(11+)时重构
- 认知复杂度:超过 15 时重构
- 可维护性:低于 65 时重构
- 每个代码文件的行数:显著超过 500 行时拆分,除非无法避免
手动识别模式
使用 Explore Agent 查找以下会增加复杂度的模式:
魔法数字和字符串:
- 散布在代码中的数字字面量(0、1、-1 除外)
- 用作键、阈值或配置的字符串字面量
- 搜索多位数:
grep -rE '\b[0-9]{2,}\b' --include='*.py' - 查找:费用计算、超时值、缓冲区大小、正则表达式模式
重复的字段操作:
- 多个类似的 if 语句,用于检查或设置对象字段
- 模式:
if obj.field: obj.field = func(obj.field) - 搜索在不同字段上执行类似操作、包含 5 行以上代码的函数
- 候选项:配置加载、验证、序列化、字段清除
重复的复杂类型定义:
- 多处使用相同的复杂类型注解
- 示例模式:在多个函数/类中重复使用
Literal["a", "b", "c"] | None - 搜索:
grep -r 'Literal\[' --include='*.py',然后查找重复项 - 还包括:复杂联合类型、多次使用的嵌套泛型
- 候选项:函数参数、返回类型、类属性、
cast()调用
较长的 if/elif 链:
- 5 个以上执行类似操作的条件分支
- 通常可以用查找表或多态替代
深层嵌套代码:
- 缩进层级达到 4 层以上
- 多层嵌套循环或条件语句
重构模式
提取函数
将复杂函数拆分为职责明确的子函数:
# BEFORE - 20+ lines, complexity: 15
def process_order(order: dict) -> bool:
# Validation, payment, confirmation logic all mixed
# AFTER - Each function <5 lines, complexity: <5
def process_order(order: dict) -> bool:
return is_valid_order(order) and process_payment(order) and complete_order(order)
守卫子句
用提前返回替代嵌套条件:
# BEFORE - Deep nesting
if user:
if user.get("active"):
if user.get("verified"):
return True
return False
# AFTER - Guard clauses
if not user or not user.get("active") or not user.get("verified"):
return False
return True
查找表
用字典替代 if/elif 链:
# BEFORE - Nested conditionals (complexity: 7)
if customer == "gold" and total > 1000: return 0.20
elif customer == "gold": return 0.15
# ... more branches
# AFTER - Lookup table (complexity: 2)
RATES = {("gold", "high"): 0.20, ("gold", "low"): 0.15, ...}
return RATES.get((customer, tier), 0.0)
提取魔法数字和字符串
将散落的字面量提取到配置类中:
# BEFORE - Magic numbers throughout code
if amount < 100: base_fee = 2.50
elif amount < 1000: base_fee = 5.00
if account_type == "premium": return base_fee * 0.5
# AFTER - Configuration class
class FeeConfig:
TIER_SMALL = 100
FEE_SMALL = 2.50
PREMIUM_DISCOUNT = 0.5
if amount < FeeConfig.TIER_SMALL:
base_fee = FeeConfig.FEE_SMALL
优点:单一事实来源、易于修改、自描述,并且可以从环境变量加载
替换重复的字段操作
用遍历字段名的循环替换重复的 if 语句:
# BEFORE - 15 similar if-statements (complexity: 9)
if config.email.smtp_host:
config.email.smtp_host = substitute_secret(config.email.smtp_host, secrets)
if config.email.smtp_user:
config.email.smtp_user = substitute_secret(config.email.smtp_user, secrets)
# ... 13 more similar lines
# AFTER - Loop over field list (complexity: 3)
email_fields = ["smtp_host", "smtp_user", "smtp_password", "smtp_from"]
for field in email_fields:
if value := getattr(config.email, field, None):
setattr(config.email, field, substitute_secret(value, secrets))
模式:在验证、字段清除、转换和序列化中使用 getattr/setattr 循环
提取重复的复杂类型定义
使用 TypeAlias 替换重复的复杂类型注解:
# BEFORE - Type repeated 8 times across files
cache_mode: Literal["use", "only", "refresh"] | None
# ... used in 8 different functions, classes
# AFTER - Define once, use everywhere
CacheMode = Literal["use", "only", "refresh"]
CacheModeOptional = CacheMode | None
cache_mode: CacheModeOptional
放置位置:
- 模块级:在单个模块中使用的类型
types.py:整个项目使用的类型__init__.py:整个包导出的类型
优点:遵循 DRY 原则、名称更具语义、易于修改、减少拼写错误
验证清单
-
radon cc . -n C未报告复杂度 ≥C(11+)的函数 -
lizard -C 15 .未报告认知复杂度警告 -
radon mi . -n B未报告可维护性指数 <65 的模块 - 代码文件均不超过 500 行(除非无法避免)
- 已运行
wily build .初始化跟踪 - 重构后所有测试均通过
- 代码覆盖率保持不变或有所提高
示例
示例:降低复杂度的工作流
1. Measure: radon cc . -n C; lizard -CCN 15 .
2. Found: handlers.py:process_data (complexity D: 25)
3. Apply patterns: Extract functions, guard clauses, lookup tables
4. Result: 4 functions with complexity A-B
5. Track: wily diff HEAD~1 shows 20-point reduction
示例:应用专用模式
# Magic numbers: Search with grep, extract to config class
if amount < 100: fee = 2.50 # BEFORE
if amount < FeeConfig.TIER_SMALL: fee = FeeConfig.FEE_SMALL # AFTER
# Repetitive fields: Replace 15 if-statements with loop
for field in ["smtp_host", "smtp_user", ...]:
if value := getattr(config, field, None):
setattr(config, field, process(value))
# Complex types: Extract repeated Literal types to TypeAlias
CacheMode = Literal["use", "only", "refresh"] # Used 8 times → defined once
相关技能
- 前置条件:py-quality-setup(工具配置)、py-test-quality(重构前的安全保障)
- 前期清理:py-code-health(先移除无用代码,减少干扰)
- 强制执行:py-git-hooks(将复杂度检查添加到 pre-commit)
评论
支持 Markdown