本文目录导读:

我来详细介绍使用Radon分析Python代码复杂度的方法:
安装Radon
pip install radon
Radon支持的复杂度指标
1 圈复杂度(Cyclomatic Complexity)
衡量代码的分支复杂度
# 示例代码:complex_functions.py
def simple_function(a, b):
return a + b
def complex_function(x, y, z):
if x > 0:
if y > 0:
if z > 0:
return "all positive"
else:
return "z negative"
else:
return "y negative"
else:
return "x negative"
2 认知复杂度(Cognitive Complexity)
衡量代码的理解难度(Radon 4.0+)
命令行使用
1 分析单个文件
# 显示圈复杂度 radon cc complex_functions.py -s # 显示评分(A-F等级) radon cc complex_functions.py -a # 显示详细输出 radon cc complex_functions.py -s -n
2 分析整个项目
# 递归分析所有Python文件 radon cc my_project/ -s # 排除测试文件 radon cc my_project/ -e "test_*.py"
3 按复杂度排序
# 按复杂度降序排列 radon cc my_project/ -s --sort
Python API使用
import radon
from radon.complexity import cc_visit, cc_rank
from radon.raw import analyze
# 读取代码
with open('complex_functions.py', 'r') as f:
code = f.read()
# 分析圈复杂度
results = cc_visit(code)
for func in results:
print(f"Function: {func.name}")
print(f"Complexity: {func.complexity}")
print(f"Rank: {cc_rank(func.complexity)}")
print(f"Line: {func.lineno}")
print("---")
复杂度等级说明
def get_complexity_rank(complexity):
"""圈复杂度等级"""
ranks = {
'A': (1, 5, '低风险'),
'B': (6, 10, '较低风险'),
'C': (11, 20, '中等风险'),
'D': (21, 30, '较高风险'),
'E': (31, 40, '高风险'),
'F': (41, float('inf'), '极高的风险')
}
for rank, (min_val, max_val, desc) in ranks.items():
if min_val <= complexity <= max_val:
return f"{rank}级: {desc}"
return "未知等级"
# 示例
print(get_complexity_rank(3)) # A级
print(get_complexity_rank(15)) # C级
print(get_complexity_rank(50)) # F级
生成HTML报告
import json
from radon.complexity import cc_visit
from radon.raw import analyze
def generate_complexity_report(code, filename):
"""生成可读性报告"""
# 圈复杂度
cc_results = cc_visit(code)
# 原始指标
raw_metrics = analyze(code)
report = {
'file': filename,
'complexity': {
'functions': [],
'average': 0
},
'raw_metrics': {
'lines': raw_metrics.loc,
'code_lines': raw_metrics.sloc,
'comments': raw_metrics.comments,
'docstrings': raw_metrics.multi,
}
}
complexities = []
for func in cc_results:
func_info = {
'name': func.name,
'type': func.type,
'complexity': func.complexity,
'rank': cc_rank(func.complexity),
'line': func.lineno
}
report['complexity']['functions'].append(func_info)
complexities.append(func.complexity)
if complexities:
report['complexity']['average'] = sum(complexities) / len(complexities)
return report
# 使用示例
code = """
def func1(x):
if x > 0:
return x
return -x
def func2(a, b, c):
if a > b:
if b > c:
return a
else:
return c
else:
return b
"""
report = generate_complexity_report(code, 'example.py')
print(json.dumps(report, indent=2))
与其他工具集成
1 集成到测试框架
import pytest
from radon.complexity import cc_visit
def test_complexity():
"""确保代码复杂度不超过阈值"""
MAX_COMPLEXITY = 10
with open('my_module.py', 'r') as f:
code = f.read()
results = cc_visit(code)
for func in results:
assert func.complexity <= MAX_COMPLEXITY, \
f"{func.name} 复杂度 {func.complexity} 超过阈值 {MAX_COMPLEXITY}"
2 集成到CI/CD
# .github/workflows/complexity-check.yml
name: Code Complexity Check
on: [push, pull_request]
jobs:
complexity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install radon
- name: Check complexity
run: |
radon cc . -a --exclude "tests/*,.venv/*"
实际案例分析
# bad_complexity.py - 高复杂度示例
def process_data(data, options):
"""处理数据的高复杂度函数"""
if options.get('validate'):
if not data:
return {'error': 'No data'}
if options.get('type') == 'csv':
if isinstance(data, str):
lines = data.split('\n')
rows = [line.split(',') for line in lines]
if options.get('header'):
if rows:
headers = rows[0]
data = rows[1:]
else:
return {'error': 'Empty CSV'}
else:
headers = None
data = rows
else:
return {'error': 'Invalid CSV format'}
elif options.get('type') == 'json':
import json
try:
if isinstance(data, str):
data = json.loads(data)
if isinstance(data, dict):
if options.get('flatten'):
flattened = {}
for key, value in data.items():
if isinstance(value, dict):
for sub_key, sub_value in value.items():
flattened[f"{key}_{sub_key}"] = sub_value
else:
flattened[key] = value
data = flattened
except json.JSONDecodeError:
return {'error': 'Invalid JSON'}
else:
return {'error': f'Unsupported type: {options.get("type")}'}
# ... 更多条件和循环
return {'result': data}
# 复杂度分析结果
# radon cc bad_complexity.py -s
# 会显示函数复杂度较高
改进高复杂度代码
# good_complexity.py - 重构后的低复杂度代码
class DataProcessor:
"""处理数据类"""
def process(self, data, options):
"""主处理方法"""
if options.get('validate'):
validation_result = self._validate_data(data, options)
if validation_result['error']:
return validation_result
processed_data = self._process_by_type(data, options)
return {'result': processed_data}
def _validate_data(self, data, options):
"""验证数据"""
if not data:
return {'error': 'No data'}
return {'error': None}
def _process_by_type(self, data, options):
"""根据类型处理数据"""
processors = {
'csv': self._process_csv,
'json': self._process_json,
}
processor = processors.get(options.get('type'))
if not processor:
return {'error': f'Unsupported type: {options.get("type")}'}
return processor(data, options)
def _process_csv(self, data, options):
"""处理CSV数据"""
if not isinstance(data, str):
return {'error': 'Invalid CSV format'}
rows = [line.split(',') for line in data.split('\n')]
return self._extract_data(rows, options.get('header'))
def _process_json(self, data, options):
"""处理JSON数据"""
import json
parsed_data = self._parse_json(data)
if parsed_data is None:
return {'error': 'Invalid JSON'}
if options.get('flatten'):
parsed_data = self._flatten_dict(parsed_data)
return parsed_data
# 更多独立的小函数...
最佳实践
1 设置复杂度阈值
# 项目配置
COMPLEXITY_THRESHOLDS = {
'function': 10, # 函数复杂度阈值
'method': 10, # 方法复杂度阈值
'module': 30, # 模块复杂度阈值
}
2 自动化检查
# complexity_checker.py
import os
import sys
from radon.complexity import cc_visit
def check_project_complexity(project_path, max_complexity=10):
"""检查项目复杂度"""
issues = []
for root, dirs, files in os.walk(project_path):
# 跳过隐藏目录和虚拟环境
dirs[:] = [d for d in dirs if not d.startswith('.') and d != 'venv']
for file in files:
if file.endswith('.py'):
filepath = os.path.join(root, file)
with open(filepath, 'r', encoding='utf-8') as f:
try:
results = cc_visit(f.read())
for func in results:
if func.complexity > max_complexity:
issues.append({
'file': filepath,
'function': func.name,
'complexity': func.complexity,
'line': func.lineno
})
except SyntaxError:
print(f"语法错误: {filepath}")
return issues
# 使用
issues = check_project_complexity('./my_project')
if issues:
print("发现高复杂度代码:")
for issue in issues:
print(f" {issue['file']}:{issue['line']} - "
f"{issue['function']}({issue['complexity']})")
else:
print("所有代码复杂度在阈值范围内")
通过以上方法,你可以全面分析Python代码的复杂度,并持续改进代码质量。