Python:使用装饰器计算递归函数的执行时间 [英] Python: Counting executing time of a recursion function with decorator

查看:141
本文介绍了Python:使用装饰器计算递归函数的执行时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个行为与给定函数完全相似的函数,不同之处在于它会打印执行该函数所消耗的时间.就是这样:

I want to write a function which behaves exactly similar to the given function, except that it prints the time consumed in executing it. Just like this:

>>> fib = profile(fib)
>>> fib(20)
time taken: 0.1 sec
10946

这是我的代码,它将在每个函数调用中打印消息.

This is my code,and it will print message in each function call.

import time


def profile(f):
    def g(x):
        start_time = time.clock()
        value = f(x)
        end_time = time.clock()
        print('time taken: {time}'.format(time=end_time-start_time))
        return value
    return g


@profile
def fib(n):
    if n is 0 or n is 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

我上面的代码将为每个fib(n-1)打印一条消息``耗时:...'',因此会有很多消息``耗时:...''.我可以找到一种方法来仅打印fib(20)的执行时间,而不是每个fib(n-1)的执行时间吗?

My code above will print a message 'taken time:...' for each fib(n-1).So there will be many many messages 'taken time:...'. Can I find a way to just print executing time of fib(20) not every executing time of fib(n-1)?

推荐答案

我假设您的问题是我该如何编写 profile ,以便即使我装饰了一个函数也只打印一条消息"可以自称?"

I'm assuming your question is "how do I write profile so that it only prints one message even when I decorate a function that can call itself?"

您可以跟踪当前正在计时的功能.这样,如果一个函数调用了它自己,您就知道您已经在对它进行进一步的计时了,并且不需要为第二个实例做任何事情.

You could keep track of which functions are currently being timed. That way, if a function calls itself, you know that you're already timing it further up the stack, and don't need to do anything for the second instance.

def profile(f, currently_evaluating=set()):
    #`currently_evaluating` will persist across all decorated functions, due to "mutable default argument" behavior.
    #see also http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument
    def g(x):
        #don't bother timing it if we're already doing so
        if f in currently_evaluating: 
            return f(x)
        else:
            start_time = time.clock()
            currently_evaluating.add(f)
            try:
                value = f(x)
            finally:
                currently_evaluating.remove(f)
            end_time = time.clock()
            print('time taken: {time}'.format(time=end_time-start_time))
            return value
    return g


如果您使用的是3.X,则可以使用 nonlocal 关键字来减少可变的默认参数怪异度.


If you're using 3.X, you can cut down on mutable default argument weirdness by using the nonlocal keyword.

def profile(f):
    is_evaluating = False
    def g(x):
        nonlocal is_evaluating
        if is_evaluating:
            return f(x)
        else:
            start_time = time.clock()
            is_evaluating = True
            try:
                value = f(x)
            finally:
                is_evaluating = False
            end_time = time.clock()
            print('time taken: {time}'.format(time=end_time-start_time))
            return value
    return g

这篇关于Python:使用装饰器计算递归函数的执行时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆