如何开发Python装饰器获取函数内对象的真实内存占用?
解决Python装饰器获取目标函数内部对象内存大小的问题
你的问题核心在于作用域隔离:装饰器里的wrapper函数调用locals()时,只能拿到它自己的局部变量(比如args、kwargs),而被装饰的my_function的内部变量存在于它专属的执行作用域中,默认情况下外部根本碰不到。
另外还要提一句:你原来的代码还犯了个小错误——你统计的是变量名(字符串,比如"nums")的内存,而不是变量指向的实际对象的大小,这也得一起修正。
下面是能正常工作的装饰器实现:
from pympler import asizeof import functools import sys def get_size(func): @functools.wraps(func) def wrapper(*args, **kwargs): target_locals = {} def trace_func(frame, event, arg): # 检测是否进入目标函数的调用 if event == 'call' and frame.f_code == func.__code__: # 继续跟踪这个函数的后续事件(比如返回) return trace_func # 检测目标函数执行完毕准备返回 elif event == 'return' and frame.f_code == func.__code__: # 复制目标函数的局部变量字典 nonlocal target_locals target_locals = frame.f_locals.copy() # 保存原跟踪函数,避免影响其他代码 original_trace = sys.gettrace() sys.settrace(trace_func) try: # 执行目标函数 func(*args, **kwargs) finally: # 恢复原跟踪配置 sys.settrace(original_trace) # 输出内存统计结果 print(f"Memory allocation (KB) of variables of the function {func.__name__!r}") for var_name, var_obj in target_locals.items(): size_kb = asizeof.asizeof(var_obj) / 10**3 print(f"size of object {var_name!r} is {size_kb:.3f} KB") return wrapper @get_size def my_function(): nums = [1,2,3,4,5] more_nums = [nums, nums, nums, nums, nums] my_function()
运行这段代码后,你会得到预期的输出:
Memory allocation (KB) of variables of the function 'my_function' size of object 'nums' is 0.120 KB size of object 'more_nums' is 0.248 KB
代码原理说明
sys.settrace():这是Python提供的全局跟踪工具,能监听函数调用、返回等执行事件。我们用它来"偷偷"捕获目标函数的执行状态。- 跟踪逻辑:自定义的
trace_func会识别目标函数的调用和返回事件,当函数执行完毕返回时,复制它的f_locals(局部变量字典)——这就是我们要找的nums、more_nums所在的地方。 - 恢复原状态:在
finally块中恢复原来的跟踪函数,确保我们的装饰器不会干扰其他代码的正常执行。
为什么原来的代码失效?
你之前的locals()调用属于wrapper函数的作用域,只能拿到wrapper自己的变量;而my_function的局部变量在它自己的栈帧里,执行完毕后就会被销毁,除非我们用跟踪的方式提前捕获。另外,你之前用asizeof.asizeof(key)统计的是变量名的大小,正确的做法应该是统计变量指向的对象var_obj的大小。
内容的提问来源于stack exchange,提问作者G. Macia
相关产品推荐
相关产品推荐

