| name | Python分析器 |
| description | 当进行Python代码审查、性能优化、类型安全检查或测试策略规划时,分析Python代码质量和最佳实践。 |
| license | MIT |
Python分析器技能
概述
Python让编写糟糕代码变得容易。分析代码质量以防止技术债务。
核心原则: Python让编写糟糕代码变得容易。分析代码质量以防止技术债务。
何时使用
始终:
- Python代码审查
- 性能优化
- 类型安全检查
- 测试策略规划
- 代码重构
- 架构设计评审
触发短语:
- "分析Python代码"
- "Python性能优化"
- "代码质量检查"
- "Python最佳实践"
- "类型安全分析"
- "测试覆盖率"
Python分析功能
代码质量
- PEP 8规范检查
- 代码复杂度分析
- 代码重复检测
- 命名规范检查
- 文档字符串审查
性能分析
- 瓶颈识别
- 内存使用分析
- 算法复杂度评估
- 并发性能检查
- I/O优化建议
类型安全
- 类型注解检查
- 类型推断分析
- 类型错误检测
- mypy兼容性
- 运行时类型验证
常见Python问题
代码风格问题
问题:
不符合PEP 8编码规范
错误示例:
- 变量名使用驼峰命名
- 行长度超过79字符
- 缺少空行分隔
- 导入语句不规范
解决方案:
1. 使用black自动格式化
2. 配置flake8检查
3. 使用isort整理导入
4. 遵循PEP 8指南
性能问题
问题:
Python代码性能低下
错误示例:
- 在循环中使用+拼接字符串
- 不必要的列表推导
- 全局变量访问
- 缺少缓存机制
解决方案:
1. 使用join拼接字符串
2. 优化数据结构选择
3. 使用局部变量
4. 实现缓存策略
类型安全问题
问题:
缺少类型注解导致运行时错误
错误示例:
- 函数参数无类型提示
- 返回值类型不明确
- 可选参数未标注
- 泛型使用不当
解决方案:
1. 添加类型注解
2. 使用Optional标注可选值
3. 使用TypeVar定义泛型
4. 运行mypy检查
代码实现示例
Python代码分析器
import ast
import os
import re
from collections import defaultdict
from typing import List, Dict, Any, Optional
from dataclasses import dataclass
from pathlib import Path
@dataclass
class CodeIssue:
"""代码问题"""
file_path: str
line_number: int
column: int
severity: str
message: str
rule_id: str
suggestion: Optional[str] = None
@dataclass
class FunctionMetrics:
"""函数指标"""
name: str
line_start: int
line_end: int
complexity: int
arguments: int
returns: int
docstring: bool
type_annotations: bool
@dataclass
class ClassMetrics:
"""类指标"""
name: str
line_start: int
line_end: int
methods: int
attributes: int
inheritance_depth:
docstring:
:
():
.config = config .get_default_config()
.issues: [CodeIssue] = []
.function_metrics: [FunctionMetrics] = []
.class_metrics: [ClassMetrics] = []
.imports: [, []] = defaultdict()
.complexity_threshold = .config.get(, )
() -> :
{
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
}
() -> [, ]:
:
(file_path, , encoding=) f:
content = f.read()
tree = ast.parse(content, filename=file_path)
.issues = []
.function_metrics = []
.class_metrics = []
.imports = defaultdict()
.check_style(file_path, content)
.analyze_ast(tree, file_path)
.check_complexity(tree, file_path)
.check_type_safety(tree, file_path)
.check_documentation(tree, file_path)
{
: file_path,
: .issues,
: .function_metrics,
: .class_metrics,
: (.imports),
: .generate_summary()
}
SyntaxError e:
{
: file_path,
: ,
: [CodeIssue(
file_path=file_path,
line_number=e.lineno ,
column=e.offset ,
severity=,
message=,
rule_id=
)]
}
Exception e:
{
: file_path,
: ,
: []
}
() -> [, ]:
results = []
all_issues = []
root, dirs, files os.walk(directory):
dirs[:] = [d d dirs d.startswith() d [, , ]]
file files:
file.endswith():
file_path = os.path.join(root, file)
result = .analyze_file(file_path)
results.append(result)
all_issues.extend(result.get(, []))
{
: directory,
: results,
: (all_issues),
: .categorize_issues(all_issues),
: .generate_recommendations(all_issues)
}
() -> :
lines = content.split()
line_num, line (lines, ):
(line) > .config[]:
.issues.append(CodeIssue(
file_path=file_path,
line_number=line_num,
column=.config[],
severity=,
message=,
rule_id=,
suggestion=
))
line.endswith():
.issues.append(CodeIssue(
file_path=file_path,
line_number=line_num,
column=(line.rstrip()),
severity=,
message=,
rule_id=,
suggestion=
))
line:
.issues.append(CodeIssue(
file_path=file_path,
line_number=line_num,
column=line.find(),
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
node ast.walk(tree):
(node, ast.Import):
alias node.names:
.imports[].append(alias.name)
(node, ast.ImportFrom):
module = node.module
alias node.names:
.imports[].append()
node ast.walk(tree):
(node, ast.FunctionDef):
.analyze_function(node, file_path)
(node, ast.ClassDef):
.analyze_class(node, file_path)
() -> :
complexity = .calculate_complexity(node)
args = (node.args.args) + (node.args.kwonlyargs)
node.args.vararg:
args +=
node.args.kwarg:
args +=
returns = ([n n ast.walk(node) (n, ast.Return)])
has_docstring = (ast.get_docstring(node) )
has_type_annotations = (
(arg.annotation arg node.args.args)
(node.returns )
)
metrics = FunctionMetrics(
name=node.name,
line_start=node.lineno,
line_end=node.end_lineno node.lineno,
complexity=complexity,
arguments=args,
returns=returns,
docstring=has_docstring,
type_annotations=has_type_annotations
)
.function_metrics.append(metrics)
complexity > .complexity_threshold:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
has_docstring .config[]:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
has_type_annotations .config[]:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
methods =
attributes =
item node.body:
(item, ast.FunctionDef):
methods +=
(item, ast.Assign):
target item.targets:
(target, ast.Name):
attributes +=
inheritance_depth = .calculate_inheritance_depth(node)
has_docstring = (ast.get_docstring(node) )
metrics = ClassMetrics(
name=node.name,
line_start=node.lineno,
line_end=node.end_lineno node.lineno,
methods=methods,
attributes=attributes,
inheritance_depth=inheritance_depth,
docstring=has_docstring
)
.class_metrics.append(metrics)
inheritance_depth > :
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
has_docstring .config[]:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
complexity =
child ast.walk(node):
(child, (ast.If, ast.While, ast.For, ast.AsyncFor)):
complexity +=
(child, ast.ExceptHandler):
complexity +=
(child, ast.With, ast.AsyncWith):
complexity +=
(child, ast.BoolOp):
complexity += (child.values) -
complexity
() -> :
node.bases:
max_depth =
base node.bases:
(base, ast.Name):
max_depth = (max_depth, )
max_depth
() -> :
node ast.walk(tree):
(node, (ast.For, ast.While, ast.If)):
depth = .calculate_nesting_depth(node)
depth > :
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
max_depth = current_depth
child ast.iter_child_nodes(node):
(child, (ast.For, ast.While, ast.If, ast.With, ast.Try)):
child_depth = .calculate_nesting_depth(child, current_depth + )
max_depth = (max_depth, child_depth)
max_depth
() -> :
node ast.walk(tree):
(node, ast.FunctionDef):
.check_function_types(node, file_path)
(node, ast.Attribute):
.check_none_safety(node, file_path)
() -> :
.config[]:
arg node.args.args:
arg.annotation:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
node.returns:
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
(node.value, ast.Name) node.value. == :
.issues.append(CodeIssue(
file_path=file_path,
line_number=node.lineno,
column=node.col_offset,
severity=,
message=,
rule_id=,
suggestion=
))
() -> :
ast.get_docstring(tree) .config[]:
.issues.append(CodeIssue(
file_path=file_path,
line_number=,
column=,
severity=,
message=,
rule_id=,
suggestion=
))
() -> [, ]:
total_issues = (.issues)
error_count = ([i i .issues i.severity == ])
warning_count = ([i i .issues i.severity == ])
info_count = ([i i .issues i.severity == ])
{
: total_issues,
: error_count,
: warning_count,
: info_count,
: (.function_metrics),
: (.class_metrics),
: .calculate_average_complexity()
}
() -> :
.function_metrics:
total_complexity = (f.complexity f .function_metrics)
total_complexity / (.function_metrics)
() -> [, [CodeIssue]]:
categorized = {
: [],
: [],
: []
}
issue issues:
categorized[issue.severity].append(issue)
categorized
() -> [[, ]]:
recommendations = []
issue_counts = defaultdict()
issue issues:
issue_counts[issue.rule_id] +=
issue_counts[] > :
recommendations.append({
: ,
: ,
: ,
:
})
issue_counts[] > :
recommendations.append({
: ,
: ,
: ,
:
})
issue_counts[] > :
recommendations.append({
: ,
: ,
: ,
:
})
issue_counts[] > :
recommendations.append({
: ,
: ,
: ,
:
})
recommendations
():
analyzer = PythonAnalyzer()
result = analyzer.analyze_file()
()
()
directory_result = analyzer.analyze_directory()
()
()
rec directory_result[]:
()
__name__ == :
main()
Python性能分析器
import time
import cProfile
import pstats
import io
from functools import wraps
from typing import Callable, Dict, Any, List
from dataclasses import dataclass
@dataclass
class PerformanceMetric:
"""性能指标"""
function_name: str
execution_time: float
call_count: int
memory_usage: int
cpu_usage: float
class PythonPerformanceAnalyzer:
def __init__(self):
self.metrics: List[PerformanceMetric] = []
self.profiles: Dict[str, cProfile.Profile] = {}
def profile_function(self, func: Callable) -> Callable:
"""函数性能分析装饰器"""
@wraps(func)
def wrapper(*args, **kwargs):
profiler = cProfile.Profile()
start_time = time.time()
profiler.enable()
try:
result = func(*args, **kwargs)
result
:
profiler.disable()
end_time = time.time()
execution_time = end_time - start_time
.record_metric(func.__name__, execution_time, profiler)
.profiles[func.__name__] = profiler
result
wrapper
() -> :
stats = pstats.Stats(profiler)
call_count =
func_info, (calls, _, _, _, _) stats.stats.items():
func_info[] == func_name:
call_count = calls
metric = PerformanceMetric(
function_name=func_name,
execution_time=execution_time,
call_count=call_count,
memory_usage=,
cpu_usage=
)
.metrics.append(metric)
() -> [, ]:
func_name .profiles:
{: }
profiler = .profiles[func_name]
stats = pstats.Stats(profiler)
hotspots = []
func_info, (calls, total_time, cum_time, _, _) stats.stats.items():
hotspots.append({
: func_info[],
: calls,
: total_time,
: cum_time
})
hotspots.sort(key= x: x[], reverse=)
{
: func_name,
: hotspots[:],
: (h[] h hotspots),
: (h[] h hotspots)
}
() -> []:
report = .get_performance_report(func_name)
suggestions = []
report:
suggestions
hotspots = report[]
hotspot hotspots[:]:
hotspot[] > :
suggestions.append(
)
hotspot[] > :
suggestions.append(
)
suggestions
():
time.sleep()
result = (i * i i ())
result
():
_ ():
slow_function()
analyzer = PythonPerformanceAnalyzer()
report = analyzer.get_performance_report()
(, report)
suggestions = analyzer.optimize_suggestions()
(, suggestions)
__name__ == :
main()
Python最佳实践
代码风格
- PEP 8: 遵循Python编码规范
- 自动格式化: 使用black和isort
- 代码检查: 使用flake8和pylint
- 类型注解: 使用typing模块
性能优化
- 算法选择: 选择合适的数据结构
- 缓存机制: 使用functools.lru_cache
- 并发编程: 使用asyncio和multiprocessing
- 内存管理: 避免内存泄漏
安全实践
- 输入验证: 验证外部输入
- SQL注入: 使用参数化查询
- 依赖管理: 定期更新依赖
- 代码审计: 定期安全检查
相关技能
- python-testing - Python测试
- python-performance - Python性能优化
- python-security - Python安全
- python-architecture - Python架构设计