Python 关于decorator函数的一些事情

Python 关于decorator函数的一些事情,python,recursion,decorator,python-decorators,functools,Python,Recursion,Decorator,Python Decorators,Functools,我试图理解一个斐波那契序列的例子,它使用一个装饰器来存储已经计算过的数字的值。例如,fib(5)将被计算,当我们到达fib(6)时,它不会再次计算fib(5)。。。 我对装饰师有点了解,但有些事情让我困惑。我对下面的代码有几个问题 from functools import wraps def dec(func): values = {} @wraps(func) def wrap(*args): if args not in values:

我试图理解一个斐波那契序列的例子,它使用一个装饰器来存储已经计算过的数字的值。例如,
fib(5)
将被计算,当我们到达
fib(6)
时,它不会再次计算
fib(5)
。。。 我对装饰师有点了解,但有些事情让我困惑。我对下面的代码有几个问题

from functools import wraps
def dec(func):
    values = {}
    @wraps(func)
    def wrap(*args):
        if args not in values:
            values[args] = func(*args)
        return values[args]
    return wrap

@dec
def fib(n):
    if n <= 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)
从functools导入包装
def dec(func):
值={}
@包装(func)
def wrap(*args):
如果参数不在值中:
值[args]=func(*args)
返回值[args]
回程包装
@十二月
def纤维(n):
如果n什么是
*args
*args
将所有剩余参数作为元组进行匹配。举个例子:

def f(*args):
    print(args)
f('a', 'b')
# output: ('a', 'b')
在本例中,它用于使用完全相同的参数调用内部函数,无论它们可能是什么。您还可以使用双星来匹配关键字参数,目前只有位置参数起作用

递归调用fib时会发生什么 使用
@
装饰函数时,引用会立即被覆盖。当
fib
在自身内部调用
fib()
时,它首先在局部范围中查找具有该名称的变量。由于没有,它将查找下一个作用域,在本例中是全局作用域。在那里,它找到一个名为
fib
的变量,该变量实际上是从decorator分配给
wrap
函数的,原始
fib
的“上下文”是
func

查找闭包以了解有关其工作原理的更多信息

为什么装饰器在结尾处返回
wrap
装饰器基本上用一个函数替换另一个函数。它像调用函数一样调用
@
之后的变量,然后用该调用的结果替换
def
定义的新函数。在这种情况下,您希望将其替换为
wrap
,这是一个新函数,可以调用也可以不调用旧函数


如果您不返回任何内容,变量
fib
将被简单地设置为
None
(默认返回值),并且您不能调用
None
1-您完全正确。不需要使用“*”,因为您只检查传递给函数的值。所以简单地称之为“n”

2-首先让我们来弄清楚,在上面加上“@dec”后,标签“fib”是什么?实际上,它现在是装饰器内部的内部函数(我指的是“包装”函数)。为什么?因为@dec实际上是这样做的:

fib = dec(fib)
所以称为“dec”装饰器,它返回什么?“包装”功能。什么是“包装”功能?它是一个包含“值”字典的闭包

无论何时调用decorator,decorator的主体只执行一次。所以只有一个“值”字典。在执行“dec”装饰器主体的过程中还会发生什么?只返回对“wrap”函数的引用。就这样

现在,当您调用“fib”函数(最初是“wrap”函数)时,这个闭包正常运行,因为它只是一个递归函数,只是它有额外的缓存功能


3-因为您需要有一个内部函数的句柄(这里是“wrap”函数)。您想稍后调用它来计算斐波那契。

只需添加一些打印语句,您就可以很好地了解这里的情况,例如:

from functools import wraps
def dec(func):
    values = {}
    @wraps(func)
    def wrap(*args):
        print("args: ", args, " *args:", *args, args not in values, values)
        if args not in values:
            values[args] = func(*args)
        return values[args]
    print("Wrap", wrap)
    return wrap

@dec
def fib(n):
    if n <= 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

print("Answer", fib(5))
从functools导入包装
def dec(func):
值={}
@包装(func)
def wrap(*args):
打印(“args:,args,”*args:,*args,args不在值中,值中)
如果参数不在值中:
值[args]=func(*args)
返回值[args]
打印(“包装”,包装)
回程包装
@十二月
def纤维(n):
如果n
Wrap <function fib at 0x7facac4b70d0>
args:  (5,)  *args: 5 True {}
args:  (4,)  *args: 4 True {}
args:  (3,)  *args: 3 True {}
args:  (2,)  *args: 2 True {}
args:  (1,)  *args: 1 True {(2,): 1}
args:  (2,)  *args: 2 False {(2,): 1, (1,): 1, (3,): 2}
args:  (3,)  *args: 3 False {(2,): 1, (1,): 1, (3,): 2, (4,): 3}
Answer 5