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

为何Python带参重试装饰器中仅delay_secs需nonlocal声明?

问题:Python重试装饰器中仅delay_secs触发UnboundLocalError的原因

我实现了一个带参数的Python重试装饰器,代码如下:

import functools
import time

def retry(max_tries: int = 3, delay_secs: float = 1, backoff: float = 1.5):
    print("level 1:", max_tries, delay_secs, backoff)
    def decorator(func):
        print("level 2:", max_tries, delay_secs, backoff)
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal delay_secs  ## UnboundLocalError if remove this line
            print("level 3:", max_tries, delay_secs, backoff)

            for attempt in range(max_tries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"attempt {attempt} Exception: {e}  Sleeping {delay_secs}")
                    time.sleep(delay_secs)
                    delay_secs *= backoff
            print("exceeded maximun tries")
            raise e

        return wrapper

    return decorator

@retry(max_tries=4, delay_secs=1, backoff=1.25)
def something():
    raise Exception("foo")

something()

当移除nonlocal delay_secs语句时,会触发UnboundLocalError,但max_tries和backoff参数却无此问题。即使调整参数顺序或重命名参数,仍只有delay_secs参数存在作用域问题。使用Python 3.9.2版本、Debian 11系统,恳请解释该现象的原因。


解答

这是由Python的变量作用域解析规则导致的,核心区别在于变量是否在函数内部被赋值:

  1. 仅读取变量的情况(max_tries、backoff)
    在wrapper函数中,max_tries只被用来生成循环范围(range(max_tries)),backoff只被用来参与计算(delay_secs *= backoff里的backoff是读取操作)。Python会自动向上查找外层嵌套作用域(这里是retry函数的作用域)中的同名变量,不会将它们标记为wrapper的局部变量,因此不会报错。

  2. 存在赋值操作的情况(delay_secs)
    delay_secs *= backoff本质是delay_secs = delay_secs * backoff,属于赋值操作。Python的规则是:如果函数内部对某个变量进行赋值,就会默认该变量是当前函数的局部变量,不再向上查找外层作用域的同名变量。
    但在执行print(f"attempt {attempt} Exception: {e} Sleeping {delay_secs}")时,delay_secs作为局部变量还未被定义(赋值操作在time.sleep(delay_secs)之后),因此触发UnboundLocalError。

  3. nonlocal的作用
    nonlocal delay_secs语句明确告诉Python:这个变量不是wrapper的局部变量,而是来自外层嵌套函数(retry函数的作用域)的变量。这样Python会在外层作用域查找它,同时允许对其进行修改,避免了作用域冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:40:18