如果不启用跟踪,则无法执行此操作;这会伤害表现.调用函数时会构造函数本地,并在函数返回时进行清理,因此没有其他方法可以从装饰器访问这些本地函数.
您可以使用sys.settrace()插入跟踪功能,然后响应Python解释器发送该功能的事件.我们想要做的只是跟踪修饰函数,并在函数返回时记录本地:
import sys
import threading
def show_guts(f):
sentinel = object()
gutsdata = threading.local()
gutsdata.captured_locals = None
gutsdata.tracing = False
def trace_locals(frame, event, arg):
if event.startswith('c_'): # C code traces, no new hook
return
if event == 'call': # start tracing only the first call
if gutsdata.tracing:
return None
gutsdata.tracing = True
return trace_locals
if event == 'line': # continue tracing
return trace_locals
# event is either exception or return, capture locals, end tracing
gutsdata.captured_locals = frame.f_locals.copy()
return None
def wrapper(*args, **kw):
# preserve existing tracer, start our trace
old_trace = sys.gettrace()
sys.settrace(trace_locals)
retval = sentinel
try:
retval = f(*args, **kw)
finally:
# reinstate existing tracer, report, clean up
sys.settrace(old_trace)
for key, val in gutsdata.captured_locals.items():
print '{}: {!r}'.format(key, val)
if retval is not sentinel:
print 'Returned: {!r}'.format(retval)
gutsdata.captured_locals = None
gutsdata.tracing = False
return retval
return wrapper
示范:
>>> @show_guts
... def foo(a,b):
... biz = str(a)
... baz = str(b)
... return biz + baz
...
>>> result = foo("banana","phone")
a: 'banana'
biz: 'banana'
b: 'phone'
baz: 'phone'
Returned: 'bananaphone'