使用 python 装饰器调用递归函数的次数

Posted

技术标签:

【中文标题】使用 python 装饰器调用递归函数的次数【英文标题】:Number of calls of recursive function with python decorators 【发布时间】:2019-08-02 09:44:10 【问题描述】:

我有以下关于功能装饰器的代码块,我想在第二次调用fib() 时将变量wrapper.calls 初始化为0,因为我知道在第一次运行时它会给出正确答案之后,它的行为就像对以前的输出求和一样。我的问题是如何通过仅更改装饰器分析器来解决此问题?

这是我的代码:

from functools import wraps
import time


def profiler(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.calls += 1
        return func(*args, **kwargs)
    wrapper.calls = 0
    return wrapper

@profiler
def fib(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)


fib(1)
print(fib.calls)
fib(2)
print(fib.calls)

此程序执行后的输出:

1
4

预期输出

1 
3

【问题讨论】:

【参考方案1】:

因为calls = 0 仅在fib = profiler(fib) 处初始化。

如果你只执行

fib(2)
print(fib.calls)

它将是 3

for input_n in (1, 2):
    fib = profiler(fib)
    fib(input_n)
    print(fib.calls)

会如你所愿

1
3

【讨论】:

我想更改装饰器分析器以避免这种情况(执行后该程序的输出),而不是调用函数fib()的代码。【参考方案2】:
def profiler(func):

    calls = 0

    @wraps(func)
    def wrapper(*args, **kwargs): 
        nonlocal calls
        if not calls:
            wrapper.calls = 0

        calls += 1
        result = func(*args, **kwargs)
        calls -= 1
        wrapper.calls += 1

        return result
    return wrapper

【讨论】:

以上是关于使用 python 装饰器调用递归函数的次数的主要内容,如果未能解决你的问题,请参考以下文章

python 基础 11 带参数装饰器与递归函数

python函数装饰器内置函数json及模块

进阶学Python:Python的递归函数和装饰器

python--递归函数匿名函数嵌套函数高阶函数装饰器生成器迭代器

用于时间递归函数的 Python 装饰器

引用和函数引用,函数嵌套闭包,装饰器以及递归