奇怪的 python 闭包变量访问

Strange python closure variable access

提问人:FlashDD 提问时间:10/9/2022 更新时间:10/9/2022 访问量:35

问:

在尝试实现带有闭包的装饰器时,我遇到了一个有点奇怪的行为,其中可以读取变量,但如果稍后尝试赋值它,它甚至在赋值之前就变得未定义。

def run_once(fn):
    to_run = True

    def decorated(*args, **kwargs):
        if to_run:
            print(to_run)    #this access works
            #to_run = False  #while this doesn't
            return fn(*args, **kwargs)

    return decorated


class A:
    def __init__(self):
        self.c=0
    @run_once
    def method1(self):
        self.c+=1
        print(f"Ran {self.c} times")

a=A()
a.method1()
a.method1()
a.method1() 

上面的代码运行。

但如果未注释,则失败,并在赋值前引用 UnboundLocalError: local variable 'to_run'to_run = False

我发现我能阅读它真的很奇怪,但是如果我尝试在 if 的正文中分配它,它会在以前没有的地方失败。

我是否遗漏了一些明显的范围界定规则?

Python 方法 范围 闭包装饰

评论


答:

4赞 rdas 10/9/2022 #1

由于您正在尝试从外部范围修改变量,因此您需要告诉 python 您正在尝试从外部范围访问该变量:

def run_once(fn):
    to_run = True

    def decorated(*args, **kwargs):
        nonlocal to_run  # use the variable from outer scope
        if to_run:
            print(to_run)
            to_run = False  # set the flag in the outer scope
            return fn(*args, **kwargs)

    return decorated

结果:

True
Ran 1 times

评论

1赞 Tom Karzes 10/9/2022
@FlashDD 在函数中,如果您不对变量进行任何赋值,它将自动在更高的范围内查找它。但是,如果您确实从函数中的任何位置分配给它,那么它将使其成为该函数的局部变量,除非您(从函数内部)显式将其声明为 或 。请注意,这是在 Python 3 中添加的。globalnonlocalnonlocal