执行、闭包和范围



假设我想用exec实现一个身份装饰器(即,它不应该对没有参数的函数做任何事情(。当我尝试使用该装饰器定义闭包时,作用域在f_factory函数结束时仍然存在并更改接下来的内容。

我想了解为什么最后的打印返回"1b"而不是"1"。

def exec_identity(f):
    gl = globals()
    gl.update({'f':f})
    exec "def idfun(): return f()" in gl, locals()
    return idfun

class CallableClass(object):
    def __init__(self, s):
        self.s = s
    def make_callable(self):
        def f_factory(s):
            def f():
                print s
            return exec_identity(f)
            #return f
        return f_factory(self.s)


c1 = CallableClass("1")
f1 = c1.make_callable()
f1()
c1.s = "1b"
f1()
f1b = c1.make_callable()
f1b()
f1()
"""
Result:
1
1
1b
1b
"""

我知道,如果我能像这样保留 exec 语句,让它按预期工作:

exec "def idfun(): return f()" in {'f':f}, locals()

这与以下事实有关:

gl = globals()
gl.update({'f':f})

在所有情况下都适用于同一对象。

因此,全局f()与一个新的交换,并被调用。旧的,连同它的关闭,都丢失了。

gl = dict(globals())
gl.update({'f':f})

通过复制globals()字典来防止这种情况。