Python Decorator+Reflection能否有选择地创建表示单个函数调用链的对象树?
鉴于: 是否可以为f,h,i,j编写并应用一个decorator跟踪,它将在每次调用f,h,i和j时: 实例化一个“Call”对象,该对象包含函数名“f”、“h”、“i”以及arg和返回值 使用反射搜索直接或间接调用它的最近的类似修饰函数,即它会将调用传递给g,因为g没有@Tracked。 将上述“Call”对象附加到调用方“Call”对象上的“children”列表中,如果未找到合适的调用方,则附加到全局列表G中 守则:Python Decorator+Reflection能否有选择地创建表示单个函数调用链的对象树?,python,Python,鉴于: 是否可以为f,h,i,j编写并应用一个decorator跟踪,它将在每次调用f,h,i和j时: 实例化一个“Call”对象,该对象包含函数名“f”、“h”、“i”以及arg和返回值 使用反射搜索直接或间接调用它的最近的类似修饰函数,即它会将调用传递给g,因为g没有@Tracked。 将上述“Call”对象附加到调用方“Call”对象上的“children”列表中,如果未找到合适的调用方,则附加到全局列表G中 守则: G = [] @Track def f(x): a = g(x)
G = []
@Track
def f(x):
a = g(x)
b = h(x + 2)
return a + b
def g(x)
for n in range(2):
i(x + n)
@Track
def h(x):
return j(x) + 9
@Track
def i(x):
return x + 10
@Track
def j(x):
return 0
这将创建以下连接的对象树:
f(3)
j(3)
我被困在反射/遍历运行时堆栈帧部分
谢谢
实例化包含函数名“f”、“h”、“i”的“Call”对象,
以及arg和返回值
使用反射搜索最近的相似修饰函数
直接或间接呼叫它,即它将传递呼叫
对g来说,因为这不是@Tracked
在这里会有帮助的
将上述“Call”对象附加到调用方的“children”列表中
“Call”对象,如果没有合适的调用者,则调用全局列表G
发现
请记住,当您存储带有参数和返回值的调用时,它们不会被垃圾收集,内存也会增加。此外,如果存储可变对象(例如,列出稍后在调用中看到的内容)可能与正式创建调用时看到的不一样,结果如下
global_list_of_calls = defaultdict(list)
def Track(func):
def _tracked(*args, **kwargs):
res = func(*args, **kwargs)
c = Call(func.__name__, args, kwargs, res)
# do something with c, store it in a global container
global_list_of_calls.append(c)
return res
return _tracked
印刷品:
stack=[]
shift=0
def Track(func):
def wrapper(*args, **kwargs):
global shift
stack.append([])
el=stack[-1]
el.append('%s -- call(name=%s,args=%s,kwargs=%s)' % (' '*shift,func.__name__,args, kwargs))
shift+=1
res = func(*args, **kwargs)
shift-=1
el[0]+='return=%s)' % res
return res
return wrapper
展示
但有可能同意另一种说法,追溯在这里会很有帮助,
虽然回溯没有显示调用参数但回溯将有助于遍历,我确实让基本轨迹装饰器包装它的函数,捕获参数和返回值,并将它们填充到调用对象中。被困在如何找到合适的来电者。感谢回溯链接。它似乎主要是为打印输出而设计的,而不是我想要的那种用法。查看extract_tb和extract_stack函数这看起来很有希望,我没有想到要维护自己的堆栈。我将更深入地探讨如何使用这种方法。谢谢
stack=[]
shift=0
def Track(func):
def wrapper(*args, **kwargs):
global shift
stack.append([])
el=stack[-1]
el.append('%s -- call(name=%s,args=%s,kwargs=%s)' % (' '*shift,func.__name__,args, kwargs))
shift+=1
res = func(*args, **kwargs)
shift-=1
el[0]+='return=%s)' % res
return res
return wrapper
for i in stack: print i[0]
-- call(name=f,args=(3,),kwargs={})return=10)
-- call(name=i,args=(3,),kwargs={})return=13)
-- call(name=i,args=(4,),kwargs={})return=14)
-- call(name=h,args=(5,),kwargs={})return=9)
-- call(name=j,args=(5,),kwargs={})return=0)
-- call(name=j,args=(3,),kwargs={})return=0)