使用修饰符为递归函数计时

2024-06-14 06:13:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试制作一个计时器装饰器,用不同大小的列表对函数进行计时。计时器适用于insert(),我在下面已经写过了,但对于递归函数,如minimum()不起作用。对于任何大小大于1的列表,我都会得到一个递归深度错误。我该怎么补救?在

def time_long_list(func):
    import random
    def helper(*args, **kwargs):
        for item in [10, 100, 1000, 10000]:
            list = [random.randint(1, 10) for element in range(item)]
            with Timer() as clock:
                func(list)
            print(clock.interval/item)
        return func
    return helper

@time_long_list
def insert(lst):
    new_list = []
    for item in lst:
        new_list.insert(0, item)
    return new_list

@time_long_list
def minimum(lst):
    if len(lst) == 0:
        return None
    elif len(lst) == 1:
        return lst[0]
    else:
        mid = len(lst) // 2
        min1 = minimum(lst[:mid])
        min2 = minimum(lst[mid:])
        if min1 <= min2:
            return min1
        else:
            return min2

insert()
minimum()

Tags: innewforlenreturntimedefitem
1条回答
网友
1楼 · 发布于 2024-06-14 06:13:51

当你装饰一个函数时,你是在告诉python解释器接受这个函数,对它做一些“处理”,然后在全局/模块名称空间中存储对新的、修改过的函数的引用。在

根据定义,递归是一个调用自身的函数。在

因此,您在这里所要做的是不能工作的,因为您的函数现在已经被用来生成测试数据的所有代码修饰了。递归调用函数时,每次都会生成所有测试数据。由于在每一步都会生成新的测试数据,您永远无法到达递归的底部,而且不可避免地-您会达到深度限制。在

您需要的是在装饰函数时保留对原始函数的引用。然后您将有两个函数,一个生成测试数据并执行顶级递归,另一个不生成测试数据。它不是完全的递归-因为你有两个函数而不是一个,但它可能是你能做的最好的。在

通过修改decorator,我们可以保留对原始函数的引用

def time_long_list(func):
    import random
    def helper(*args, **kwargs):
        for item in [10, 100, 1000, 10000]:
            list = [random.randint(1, 10) for element in range(item)]
            with Timer() as clock:
                func(list, func)
                print(clock.interval/item)
        return func
    helper.original = func
return helper

然后修改递归函数,使其始终调用自身的原始版本,而不是修改后的版本

^{pr2}$

我不认为这是一个好的方法来做这件事-你最好离开-正如评论所建议的,创建一个单独的顶层函数来进行计时和测试数据的创建,如果可能的话。在

相关问题 更多 >