Python闭包函数失去外部变量访问

V.E*_*E.O 12 python closures decorator

我刚刚学习了python @ decorator,很酷,但很快我就发现修改后的代码出现了奇怪的问题.

def with_wrapper(param1):
    def dummy_wrapper(fn):
        print param1
        param1 = 'new'
        fn(param1)
    return dummy_wrapper

def dummy():
    @with_wrapper('param1')
    def implementation(param2):
        print param2

dummy()
Run Code Online (Sandbox Code Playgroud)

我调试它,它在print param1抛出异常

UnboundLocalError: local variable 'param1' referenced before assignment
Run Code Online (Sandbox Code Playgroud)

如果我删除 param1 = 'new'此行,而没有对外部作用域的变量进行任何修改操作(链接到新对象),则此例程可能会起作用.

这是否意味着我只制作了一个外部范围变量的副本,然后进行修改?


感谢Delnan,关闭是必不可少的.可能从这里回答: 与语言X闭包相比,Python中的闭包有哪些限制?

类似的代码:

def e(a):
    def f():
        print a
        a = '1'
    f()
e('2')
Run Code Online (Sandbox Code Playgroud)

而且这似乎是以前讨厌的全局变量:

a = '1'
def b():
    #global a
    print a
    a = '2'
b()
Run Code Online (Sandbox Code Playgroud)

这是通过添加全局符号来修复的.但是为了关闭,没有找到这样的符号.谢谢unutbu,Python 3给了我们本地化.

我从上面知道直接访问外部变量是只读的.但是看到先前读取变量(print var)也受到影响有点不舒服.

unu*_*tbu 15

当Python解析一个函数时,只要它找到一个在赋值左侧使用的变量,就会注意到它

param1 = 'new'
Run Code Online (Sandbox Code Playgroud)

它假定所有这些变量都是函数的局部变量.所以当你在这个作业之前

print param1
Run Code Online (Sandbox Code Playgroud)

发生错误,因为Python在执行print语句时没有此局部变量的值.


在Python3中,您可以通过声明param1非本地来解决此问题:

def with_wrapper(param1):
    def dummy_wrapper(fn):
        nonlocal param1
        print param1
        param1 = 'new'
        fn(param1)
    return dummy_wrapper
Run Code Online (Sandbox Code Playgroud)

在Python2中,你必须采用一种技巧,例如在列表(或其他一些可变对象)中传递param1:

def with_wrapper(param1_list):
    def dummy_wrapper(fn):
        print param1_list[0]
        param1_list[0] = 'new'   # mutate the value inside the list
        fn(param1_list[0])
    return dummy_wrapper

def dummy():
    @with_wrapper(['param1'])   # <--- Note we pass a list here
    def implementation(param2):
        print param2
Run Code Online (Sandbox Code Playgroud)

  • 也许你和我作为人类更喜欢Python首先检查`param1`变量的外部范围,如果它存在,使用它,并且只有当它不存在时,才假设它是一个局部变量.但是这会迫使Python等到运行时来决定什么是函数的局部变量.我认为这会大大降低Python的性能.每次调用函数时,都必须重新确定本地性.因此,当执行def块时,Python使用赋值来在分析时*识别局部变量*,而不是在调用函数时. (3认同)