为cProfile性能分析装饰器添加方法时遇AttributeError问题排查
问题原因与解决方案
错误原因
你遇到的问题核心在于装饰器的函数替换机制:
- 装饰器的本质是将原函数替换为内部定义的
wrapper函数,最终被赋值给原函数名(比如add)的是wrapper,而非原始的func。 - 你把
print_statistics()方法加到了原始的func对象的属性中,所以打印func.__dict__能看到该方法,但实际调用add.print_statistics()时,Python会去wrapper对象的属性里查找,自然找不到,抛出AttributeError。
简单说:你给A对象加了方法,但实际调用的是B对象,当然找不到。
解决方法
把print_statistics()方法直接加到wrapper函数对象上,同时将性能统计的cProfile.Profile实例与wrapper绑定,确保统计数据能被正确访问。
示例代码如下:
import cProfile import functools def profile_decorator(func): # 初始化性能分析器,与wrapper绑定 pr = cProfile.Profile() @functools.wraps(func) # 可选,保留原函数的名称、文档等元信息 def wrapper(*args, **kwargs): pr.enable() try: # 执行原函数 return func(*args, **kwargs) finally: pr.disable() # 定义统计打印方法,并绑定到wrapper上 def print_statistics(): # 输出性能统计表格,可指定排序规则(比如按累计耗时排序) pr.print_stats(sort='cumulative') wrapper.print_statistics = print_statistics return wrapper # 使用装饰器 @profile_decorator def add(a, b): return a + b # 调用被装饰的函数 add(1, 2) add(3, 4) # 调用统计方法 add.print_statistics()
关键说明
pr实例定义在装饰器外层,与wrapper形成闭包,确保每次调用wrapper时都能复用同一个分析器,累计统计数据。print_statistics方法直接赋值给wrapper,这样add(即wrapper)就拥有了该方法,调用时不会出错。- 使用
functools.wraps是为了让wrapper保留原函数的元信息(比如函数名、文档字符串),避免混淆,但不是必须的。
内容的提问来源于stack exchange,提问作者zaelcovsky
相关产品推荐
相关产品推荐

