Python装饰器内部机制:@语法与直接调用的执行差异疑问
Python装饰器@语法与直接调用decorator(func)()的行为差异解析
我理解Python装饰器是接收另一个函数并扩展其行为的函数。之前我以为,用@decorator装饰test()的写法,等效于直接调用decorator(test)(),比如下面这个基础示例:
def decorator(func): def wrapper(*args, **kwargs): ... res = func(*args, **kwargs) ... return res return wrapper @decorator def test(): pass
但当我给装饰器添加函数属性后,两种调用方式出现了差异:直接调用decorator(test2)()时,装饰器内的num会被重置为0;而调用@decorator装饰的test()时,num保持为5没有被重置。我想知道为什么用@语法时,装饰器没有执行num的重置操作?
def decorator(func): decorator.num = 0 def wrapper(*args, **kwargs): ... res = func(*args, **kwargs) ... return res return wrapper @decorator def test(): pass def test2(): pass decorator.num = 5 test() print(decorator.num) decorator.num = 5 decorator(test2)() print(decorator.num) # 输出结果: # 5 # 0
核心原因是**@decorator语法只会在函数定义时执行一次装饰器函数decorator,而直接调用decorator(test2)()会每次都重新执行decorator函数**。
具体拆解:
- 当你用
@decorator装饰test函数时,Python会在定义test的那一刻就调用decorator(test),此时decorator.num被设置为0,之后返回的wrapper函数会被赋值给test。后续你调用test(),其实是调用已经生成好的wrapper,不会再触发decorator函数的执行,自然不会重置num。 - 而当你执行
decorator(test2)()时,相当于每次都重新调用decorator函数:先执行decorator(test2),这一步会把decorator.num重置为0,然后返回新的wrapper,再调用这个wrapper。所以每次这么调用都会触发num的重置。
简单说,@语法是“一次性装饰”,后续调用被装饰函数不会再跑装饰器的外层逻辑;而直接调用decorator(func)()是“每次调用都重新装饰+执行”,所以会重复触发装饰器里的属性重置操作。
内容的提问来源于stack exchange,提问作者YSYS
相关产品推荐
相关产品推荐

