You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:25:27