gpt4 book ai didi

python - 装饰器:理解为什么它不刷新局部变量

转载 作者:行者123 更新时间:2023-11-30 22:46:01 25 4
gpt4 key购买 nike

我写了一个简单的装饰器:

from functools import wraps
import random

def my_dec(f):
lst = list()

@wraps(f)
def wrapper(*args):
lst.append(random.randint(0, 9))
print(lst)
return f(*args)

return wrapper

@my_dec
def foo():
print("foo called")

现在,如果我多次调用 foolst 不会被刷新。相反,它会随着时间的推移而积累。因此,多次调用 foo 会返回如下输出:

foo()
> [4]
> foo called

foo()
> [4, 9]
> foo called

foo()
> [4, 9, 1]
> foo called

...

这是为什么呢?我以为装饰器只是 my_dec(foo) 的语法糖?!我假设每次调用 my_dec 都会刷新 lst

最佳答案

你是对的......装饰器只是语法糖。具体来说:

@decorator
def foo():
pass

与以下内容完全相同:

def foo():
pass
foo = decorator(foo)

让我们更古怪一点,用另一种大部分等效的方式重写此1:

def bar():
pass
foo = decorator(bar)
del bar

希望这样写,你可以看到如果我打电话 foo很多次,我没有调用decorator好几次了。 decorator仅被调用一次(以帮助创建 foo )。

现在在您的示例中,您的装饰器在被调用时立即创建一个列表:

def my_dec(f):
lst = list() # list created here!

@wraps(f)
def wrapper(*args):
lst.append(random.randint(0, 9))
print(lst)
return f(*args)

return wrapper

函数返回wrapper被分配给您的foo ,所以当您调用foo时,您正在调用wrapper 。注意wrapper中没有代码这将重置 lst -- 仅向 lst 添加更多元素的代码所以这里没有任何内容来指示 lst 应该在调用之间“刷新”。

1(根据装饰器的作用,您可能会在函数的 __name__ 属性中看到一些差异,但在其他方面都是相同的...)

<小时/>

另请注意,您将拥有一个 lst每次调用装饰器时。如果我们喜欢并装饰的话,我们可以对这个感到疯狂foo两次:

@my_dec
@my_dec
def foo():
pass

或者我们可以装饰多个函数:

@my_dec
def foo():
pass

@my_dec
def bar():
pass

然后当我们调用foo时和bar ,我们会看到它们每个都积累了自己的(不同的)随机数列表。换句话说,每次将装饰器应用于某物时,都会创建一个新列表,并且每次调用该“某物”时,该列表都会增长。

关于python - 装饰器:理解为什么它不刷新局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41011744/

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