Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“有可能吗?”;“扩展”;在Python中使用decorator进行时间监控?_Python_Performance_Recursion_Decorator_Python Decorators - Fatal编程技术网

“有可能吗?”;“扩展”;在Python中使用decorator进行时间监控?

“有可能吗?”;“扩展”;在Python中使用decorator进行时间监控?,python,performance,recursion,decorator,python-decorators,Python,Performance,Recursion,Decorator,Python Decorators,我有一组相互使用的简单函数。例如: 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\u 1和func\u 2和func\u 2的“根”函数,依次使用func\u a和func\u b。当我调用fu

我有一组相互使用的简单函数。例如:

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\u 1
func\u 2
func\u 2
的“根”函数,依次使用
func\u a
func\u b
。当我调用
func
时,得到的结果是
z

现在我想用一个修饰符“修改”或“扩展”我的函数,这样最终(由于
func
),我不仅得到
z
,而且得到一个对象,它向我显示执行这个函数需要多少时间,函数使用了哪些函数,以及执行这些“子函数”需要多长时间以及哪些“子功能”使用了哪些“子功能”以及执行它们需要多长时间。为了使其更简单,我举了一个我期望的“额外”结果的例子:

在上面的示例中,“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
但接下来我将继续进行进一步的实现。我找不到解决办法,甚至不确定这是否可能


我的想法是使用一个装饰器来扩展传递给每个函数的参数数量。每个函数都会得到一个空列表,其中包含迄今为止使用的所有子函数,并将其自身附加到此列表。

您最好按照建议使用真实的探查器

不过,它可以通过decorator类完成。您将能够使用在所有装饰器实例之间共享的堆栈跟踪subs列表

class profile(object):
    #class variable used as a stack of subs list
    stack = [[]] 

    def __init__(self, f):
        self.f = f

    def __call__(self, *args, **kw):
        func = dict(fname = self.f.__name__)

        #append the current function in the latest pushed subs list
        profile.stack[-1].append(func)

        #push a new subs list in the stack
        profile.stack.append([]) 

        #execution time of the actual call
        t0 = time.time()
        out = self.f(*args, **kw)
        func['etime'] = time.time() - t0

        #pull the subs list from the stack
        func['subs'] = profile.stack.pop()

        return out

    @classmethod
    def show(cls):
        import json #useful to prettify the ouput
        for func in cls.stack[0]:
            print json.dumps(func, sort_keys=True, indent=4)
您必须使用
@profile
装饰所有要显示在配置文件中的函数。 请注意,在实际情况中,当修饰函数失败时,您可能希望处理异常

输出:

profile.show()

{
    "etime": 4.5, 
    "fname": "func", 
    "subs": [
        {
            "etime": 1.0, 
            "fname": "func_1", 
            "subs": []
        }, 
        {
            "etime": 3.5, 
            "fname": "func_2", 
            "subs": [
                {
                    "etime": 1.5, 
                    "fname": "func_a", 
                    "subs": []
                }, 
                {
                    "etime": 2.0, 
                    "fname": "func_b", 
                    "subs": []
                }
            ]
        }
    ]
}

decorator环绕函数,它看到它接收(参数)和发回的内容(
return
values),但不看到它调用的内容。要使用decorator实现这一点,您必须包装所有涉及在不同函数调用中共享状态的函数。或者,使用现有的剖析器。不是说你的问题是不合法的,但你几乎是在重新发明轮子。程序包中的
@profile
装饰程序正是这样做的。有关用法示例和更多详细信息,请参见。@jornsharpe,我知道。但是,如果每个函数都将同一个对象从其参数传递到其所有子函数,并且每个子函数都向该对象写入了某些内容,那么,在decorator中,在执行包装函数后,我们将获得子函数写入的信息。那么,您希望函数的一个参数实际上是用于其decorator的吗?这看起来很混乱,这意味着修饰过的函数将与未修饰过的函数具有不同的调用签名。在你开始运行自己的代码之前,先看看现有的代码分析选项。如果是这样的话,这似乎完全与Python背道而驰。最好直接将参数传递给装饰师。这往往是最容易学习的类装饰,类似于sebdestol的答案。我认为这是倒退。当您将参数传递给decorator类时,函数不是传递给call,参数不是传递给init吗?当decorator没有参数时不是,
\uuuu init\uuuuu
在函数f被修饰时被调用,并且每次f被调用时都会调用
\uuu call\uuuuuu
。如果函数调用,您可能会使用一些
try/except
逻辑fail@acushner你说得对。我想还有很多其他的方法会失败。但这并不是真正的问题。所以我宁愿保持代码简单。
{
    "etime": 4.5, 
    "fname": "func", 
    "subs": [
        {
            "etime": 1.0, 
            "fname": "func_1", 
            "subs": []
        }, 
        {
            "etime": 3.5, 
            "fname": "func_2", 
            "subs": [
                {
                    "etime": 1.5, 
                    "fname": "func_a", 
                    "subs": []
                }, 
                {
                    "etime": 2.0, 
                    "fname": "func_b", 
                    "subs": []
                }
            ]
        }
    ]
}