gpt4 book ai didi

python - 双重包装斐波那契

转载 作者:太空宇宙 更新时间:2023-11-04 04:01:55 25 4
gpt4 key购买 nike

我尝试在递归 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)

在此之后我可以访问 fib.memo 但不能访问 fib.counter,相反,如果我在计数之前用 memoize 包装 fib。

最佳答案

这个问题最初作为 How to make a chain of function decorators? 的重复问题关闭。 ,其中正确地指出使用 functools.wraps 链接装饰器可以通过将包装函数的所有属性复制到包装函数来提供帮助。

但是,我重新提出这个问题,因为使用 functools.wraps 不会完全适用于你的情况,因为你的 counter 属性是一个不可变的整数,所以有wrapscounter属性复制到wrapper中,实际上只是将其初始值0复制到wrapper中,后续对counter属性的修改包装函数不会反射(reflect)在包装器的 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

关于python - 双重包装斐波那契,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58120358/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com