双包装斐波那契

2024-04-26 10:21:11 发布

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

我尝试在递归Fibonacci函数上使用两个不同的包装器:1)计算递归次数,2)记忆计算值以减少所需的计算。你知道吗

由于每个包装函数都会在所创建的函数上创建一个新的函数属性,因此在再次包装之后,我无法再访问它。 有没有一种方法可以在不使用两种效果的单个包装函数的情况下仍然访问它?你知道吗

def count(f):
    def f1(*args):
        f1.counter += 1
        return f(*args)
    f1.counter = 0
    return f1

def memoize(f):
    def f1(*args):
        if not args in f1.memo:
            f1.memo[args] = f(*args)
        return f1.memo[args]
    f1.memo = {}
    return f1

@memoize
@count
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

在这之后我可以进入纤维备忘录但不是纤维计数器相反,如果我在数数前用memoize包装fib。你知道吗


Tags: 记忆函数returnifdefcountcounterargs
1条回答
网友
1楼 · 发布于 2024-04-26 10:21:11

这个问题最初是作为How to make a chain of function decorators?的一个副本来解决的,在这里正确地指出,使用functools.wraps来链接装饰器可以通过将包装函数的所有属性复制到包装函数来提供帮助。你知道吗

但是,我要重新讨论这个问题,因为在您的情况下使用functools.wraps不会完全起作用,因为counter属性是一个不可变的整数,所以让wrapscounter属性复制到包装器实际上只会将其初始值0复制到包装器,对包装函数的counter属性的后续更改不会反映在包装的counter属性中,这就是为什么:

from functools import wraps

def count(f):
    @wraps(f)
    def f1(*args):
        f1.counter += 1
        return f(*args)
    f1.counter = 0
    return f1

def memoize(f):
    @wraps(f)
    def f1(*args):
        if not args in f1.memo:
            f1.memo[args] = f(*args)
        return f1.memo[args]
    f1.memo = {}
    return f1

@memoize
@count
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(4))
print(fib.memo)
print(fib.counter)

输出错误:

3
{(1,): 1, (0,): 0, (2,): 1, (3,): 2, (4,): 3}
0

要解决这个问题,必须用可变对象初始化counter。由于Python本机没有可变整数,因此可以创建一个围绕整数的自定义类:

class Int:
    def __init__(self, value=0):
        self.value = value

def count(f):
    @wraps(f)
    def f1(*args):
        f1.counter.value += 1
        return f(*args)
    f1.counter = Int()
    return f1

以便:

print(fib(4))
print(fib.memo)
print(fib.counter.value)

将正确输出:

3
{(1,): 1, (0,): 0, (2,): 1, (3,): 2, (4,): 3}
5

相关问题 更多 >