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

Python装饰器中succ.calls的定义、作用域及相关技术疑问

关于Python函数属性与装饰器的疑问解答

问题背景

你遇到的装饰器代码片段:

def call_counter(func):
    def helper(x):
        helper.calls += 1
        return func(x)
    helper.calls = 0

    return helper

@call_counter
def succ(x):
    return x + 1

print(succ.calls)
for i in range(10):
    succ(i)
    
print(succ.calls)

你对succ.calls的定义、作用域感到困惑,同时自己尝试的代码出现属性错误:

def do_something():
    do_something.my_var = 6
    
print(do_something.my_var)   

核心解释:Python函数是一等对象,支持绑定属性

这种技术叫做函数属性(Function Attributes),Python中所有函数都是对象,你可以像给普通类实例添加属性一样,给函数对象绑定自定义属性,用来存储与函数相关的状态。

1. succ.calls的本质

装饰器@call_counter的执行逻辑是:

  • 当你用@call_counter装饰succ时,Python会自动把原succ函数作为参数传入call_counter。
  • call_counter内部定义了helper函数,然后给helper绑定了calls属性并初始化为0。
  • call_counter返回helper函数,此时全局变量succ不再指向原来的succ,而是指向helper这个函数对象。
  • 因此succ.calls其实就是helper.calls,调用succ(i)时执行的是helper(x),里面会累加helper.calls,也就是succ.calls。

2. 测试代码报错原因

你写的do_something.my_var是在函数内部定义的,只有当你调用do_something()之后,这个属性才会被创建并绑定到do_something函数对象上。直接执行print(do_something.my_var)时,函数还没被调用,属性不存在,所以触发AttributeError。

修正后的代码可以正常运行:

def do_something():
    do_something.my_var = 6

do_something()
print(do_something.my_var)  # 输出6

函数属性的作用域

函数属性的作用域就是函数对象本身,只要函数对象在内存中存在,你就可以通过函数名.属性名的方式访问它,不管是在函数内部还是外部。

内容的提问来源于stack exchange,提问作者Mike Wilson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:42:49