关于python:使用装饰器和调用次数查找任意函数的平均运行时间

Find average runtime of arbitrary functions using decorators and number of calls

创建一个函数,用以下方式装饰另一个函数:

1
2
3
@profile
def foo ( ... ) :
    ...

配置文件所做的是记录关于运行时的信息,以及使用时间模块的时钟函数对它所修饰的函数的调用次数。例如:

1
2
3
4
from time import clock
start = clock()
    #do something for a while
duration = clock() - start

如果全局变量PROFILE_FUNCTIONS的值为true,那么配置文件的实现应该只记录函数的运行时。不管EDOCX1的值是多少(0),您的修饰器不应该改变它所修饰的函数的行为。也就是说,修饰函数应该接受相同数量和种类的参数,并输出相同的值,就好像它没有被修饰一样。您的装饰器也必须是通用的,即我应该能够用轮廓来装饰任意函数。

在全局字典PROFILE_RESULTS中记录分析结果。字典应将分析的函数名映射到元组:(a,b),其中a是对函数的所有调用的平均运行时,b是调用函数的次数。

到目前为止,我有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time  
import operator                                        
PROFILE_RESULTS={}
funcs_ran=[]
func_runtimes=[]
func_occurences=[]

def profile(method):
    def wrapper(*args, **kw):
        startTime = clock()
        result = method(*args, **kw)
        endTime = clock()-start
        funcs_ran.append(method.__name__)
        func_runtimes.append(endTime - startTime)

@profile
def func1(sleep):
    time.sleep(sleep)

我称之为:

1
2
3
func1(0.5)
func1(1)
func1(2)

到目前为止,我有函数和运行时,但我不确定如何继续


这是怎么做的。我摆脱了大部分的全球性的东西,把剩下的改成了字典。这使得更新和检查会员资格既快捷又相当容易。其中包括取消PROFILE_RESULTS,因为我不确定你想在里面放什么。

请注意,decorator函数的编码不正确,它从未返回decorated函数/方法(它本身需要返回调用原始函数/方法的结果)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import time

func_runtimes = {}

def profile(method):
   """ Profiling decorator."""
    def wrapper(*args, **kw):
        start_time = time.clock()

        result = method(*args, **kw)

        elapsed_time = time.clock() - start_time
        func_runtimes.setdefault(method.__name__, []).append(elapsed_time)
        return result
    return wrapper  # Decorated method (need to return this).

def print_stats(method_name):
    if method_name not in func_runtimes:
        print("{!r} wasn't profiled, nothing to display.".format(method_name))
    else:
        runtimes = func_runtimes[method_name]
        total_runtime = sum(runtimes)
        average = total_runtime / len(runtimes)
        print('Stats for method: {!r}'.format(method_name))
        print('  run times: {}'.format(runtimes))
        print('  total run time: {}'.format(total_runtime))
        print('  average run time: {}'.format(average))

@profile
def func1(sleep):
    time.sleep(sleep)

func1(0.5)
func1(1)
func1(2)

print('func_runtimes:', func_runtimes)
print()
print_stats('func1')

输出:

1
2
3
4
5
6
func_runtimes: {'func1': [0.4996212506738944, 1.0000399133651898, 2.0000319306921517]}

Stats for method: 'func1'
  run times: [0.4996212506738944, 1.0000399133651898, 2.0000319306921517]
  total run time: 3.499693094731236
  average run time: 1.166564364910412