【发布时间】:2014-10-28 04:38:05
【问题描述】:
我有一组相互使用的简单函数。例如:
def func(x)
y = func_1(x)
z = func_2(y)
return z
def func_1(x):
return x + 1
def func_2(x)
a = func_a(x)
b = func_b(y)
return b
如您所见,func 是使用func_1 和func_2 和func_2 的“根”函数,而它又使用func_a 和func_b。当我调用func 时,我得到z 作为结果。
现在我想用一个装饰器“修改”或“扩展”我的函数,这样最终(由于func)我不仅得到了z,而且还有一个对象告诉我多少执行这个函数所用的时间以及该函数使用了哪些函数以及执行这些“子函数”需要多长时间以及哪些“子函数”使用了哪些“子子函数” “以及执行它们需要多长时间。为了简单起见,我举了一个我期望的“额外”结果的例子:
{
'fname' : 'func',
'etime' : 12.000,
'subs' : [
{
'fname' : 'func_1',
'etime' : 2.000,
'subs' : []
},
{
'fname' : 'func_2',
'etime' : 10,
'subs' : [
{
'fname' : 'func_a',
'etime' : 6,
'subs' : []
},
{
'fname' : 'func_b',
'etime' : 4
'subs' : []
}
]
}
]
}
在上面的例子中,“fname”表示函数名,“etime”表示执行时间(执行这个函数需要多长时间),“subs”是一个子函数列表考虑的功能。对于每个子功能,我们都有相同的键(“fname”、“etime”、“subs”)。因此,它是一个“递归”结构。如果一个函数没有使用任何函数,则“subs”映射到一个空列表。
我从以下装饰器开始:
def decorate(func):
def wrapper(*args, **kw):
d = {}
d['fname'] = func.__name__
t0 = time.time()
out = func(*args, **kw)
d['etime'] = time.time() - t0
d['subs'] = ?
?.append(d)
return wrapper
然后我与进一步的实现堆叠在一起。我找不到解决方案,甚至不确定是否可行。
我的想法是我使用装饰器来扩展传递给每个函数的参数数量。每个函数都会得到一个空列表,其中包含到目前为止使用的所有子函数,并将自身附加到该列表中。
【问题讨论】:
-
装饰器环绕函数,它查看接收到的内容(参数)并返回(
return值),但不是它调用的内容。要使用装饰器执行此操作,您必须包装所有涉及在不同函数调用之间共享状态的函数。或者,使用现有的分析器。 -
并不是说您的问题不合法,但您在这里几乎是在重新发明轮子。
profilestats包中的@profile装饰器正是这样做的。另请参阅 this answer 以获取使用示例和更多详细信息。 -
@jonrsharpe,我知道。但是,如果每个函数将同一个对象从它的参数传递给它的所有子函数,并且每个子函数都向这个对象写入一些东西,那么在装饰器中,在执行包装函数之后,我们会得到由子函数写入的信息。
-
所以你想让函数的参数之一实际上是它的装饰器?这看起来很混乱,这意味着修饰函数将具有与未修饰版本不同的调用签名。在您提交自己的代码之前,请查看用于分析代码的现有选项。
-
这似乎与 Python 完全相反,如果是这样的话。你最好直接将参数传递给装饰器。这往往是使用类装饰器最容易学习的方法,类似于 sebdestol 的答案。
标签: python performance recursion decorator python-decorators