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

问题描述

我有一个简单的装饰器来跟踪函数调用的运行时间:

I have a simple decorator to track the runtime of a function call:

def timed(f):
    def caller(*args):
        start = time.time()
        res = f(*args)
        end = time.time()
        return res, end - start
    return caller

这可以如下使用,并返回函数结果和执行时间的元组.

This can be used as follows, and returns a tuple of the function result and the execution time.

@timed
def test(n):
    for _ in range(n):
        pass
    return 0

print(test(900)) # prints (0, 2.69e-05)

很简单.但是现在我想将其应用于递归函数.正如预期的那样,将上述包装器应用于递归函数会产生带有每次递归调用次数的嵌套元组.

Simple enough. But now I want to apply this to recursive functions. Applying the above wrapper to a recursive function results in nested tuples with the times of each recursive call, as is expected.

@timed
def rec(n):
    if n:
        return rec(n - 1)
    else:
        return 0

print(rec(3)) # Prints ((((0, 1.90e-06), 8.10e-06), 1.28e-05), 1.90e-05)

编写装饰器以正确处理递归的优雅方式是什么?显然,如果是定时函数,您可以包装调用:

What's an elegant way to write the decorator so that it handles recursion properly? Obviously, you could wrap the call if a timed function:

@timed
def wrapper():
    return rec(3)

这将给出结果和时间的元组,但我希望所有这些都由装饰器处理,以便调用者不必担心为每次调用定义一个新函数.想法?

This will give a tuple of the result and the time, but I want all of it to be handled by the decorator so that the caller does not need to worry about defining a new function for every call. Ideas?

推荐答案

这里的问题并不是真正的装饰器.问题在于 rec 需要 rec 成为一个行为方式相同的函数,但您希望 rec 成为一个行为方式不同的函数.没有一种干净的方法可以用单个 rec 函数来协调它.

The problem here isn't really the decorator. The problem is that rec needs rec to be a function that behaves one way, but you want rec to be a function that behaves differently. There's no clean way to reconcile that with a single rec function.

最干净的选择是不再要求 rec 同时做两件事.不要使用装饰器符号,而是将 timed(rec) 分配给不同的名称:

The cleanest option is to stop requiring rec to be two things at once. Instead of using decorator notation, assign timed(rec) to a different name:

def rec(n):
    ...

timed_rec = timed(rec)

如果您不想要两个名称,则需要编写 rec 以了解装饰后的 rec 将返回的实际值.例如,

If you don't want two names, then rec needs to be written to understand the actual value that the decorated rec will return. For example,

@timed
def rec(n):
    if n:
        val, runtime = rec(n-1)
        return val
    else:
        return 0

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

09-16 12:16