我猜不是装饰器本身弄乱了您的分析,而是装饰器创建的 包装函数。发生这种情况是因为所有包装函数都具有相同的名称。要解决这个问题,只需让装饰器更改包装函数的名称即可。
def decorator(func):
def wrapper(*args):
print "enter func", func.__name__
return func(*args)
wrapper.__name__ += "_" + func.__name__
return wrapper
您也可以使用functools.wraps(),但是包装函数的名称将与它所包装的函数的名称相匹配。我想这对于分析来说是可以的。
现在,函数的代码对象也有了名字。 Python 不在堆栈上存储对函数的引用,只存储对代码对象的引用,因此如果分析器从堆栈帧中获取包装函数的名称,它将获取此名称。以通常方式定义的包装器共享代码对象(即使函数对象不同),除非您为每个包装器函数显式重建代码对象和函数对象。这是相当多的工作并且非常特定于 CPython(甚至可能是特定于版本的)。但你可以这样做:
from types import FunctionType, CodeType
def decorator(func):
def wrapper(*args):
print "enter func", func.__name__
return func(*args)
name = wrapper.__name__ + "_" + func.__name__
func_code = wrapper.func_code
new_code = CodeType(
func_code.co_argcount, func_code.co_nlocals, func_code.co_stacksize,
func_code.co_flags, func_code.co_code, func_code.co_consts,
func_code.co_names, func_code.co_varnames, func_code.co_filename,
name, func_code.co_firstlineno, func_code.co_lnotab,
func_code.co_freevars, func_code.co_cellvars)
wrapper = FunctionType(
new_code, wrapper.func_globals, name, wrapper.func_defaults,
wrapper.func_closure)
return wrapper
函数的名称和代码对象的名称都在这里设置为wrapper_originalfuncname,因此它们应该与分析器中的包装函数分开计算。您可以轻松地将它们设置为原始函数的名称,以便它们的运行时间将与原始函数的名称一起滚动。