Python闭包的工作原理

2024-03-28 19:52:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图理解闭包在Python中是如何工作的,我发现了以下代码片段:

def closure():
    count = 0
    def inner():
        nonlocal count
        count += 1
        print(count)
    return inner

start = closure()
start() # prints 1
start() # prints 2
start() # prints 3

我可以理解这段代码,因为当inner函数被定义时,封闭作用域有一个名为count的变量,值为0,内部函数将remember这个值

但是,如果我将count = 0移到内部函数下面,那么代码会变成:

def closure():
    def inner():
        nonlocal count
        count += 1
        print(count)
    count = 0
    return inner

start = closure()
start() # prints 1
start() # prints 2
start() # prints 3

令我惊讶的是,代码仍然可以很好地工作,这让我很困惑。当inner被定义时,变量count不存在于封闭作用域中,那么inner函数怎么能够记住此时命名空间中还不存在的值呢?你知道吗

是不是因为Python中也存在类似于JS的变量hoisting的东西?你知道吗


Tags: 函数代码return定义defcountprints作用域
2条回答

Resolution of Names

If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.

(我的)

赋值是name binding operations,因此只要count = 0存在于函数中的任何地方,count被认为是该函数的局部变量,inner将引用该变量。(不过,如果在将值赋给count之前调用inner(),则会得到一个异常。)

在这两个示例中,您都收到start变量中closure方法返回的值,即执行closure方法并返回内部局部方法。因此count变量也被定义并用值0初始化

当您使用start()调用inner方法时,该方法将被执行,此时,在这两种情况下,count变量已经存在

但是如果你有这样的代码,那么就会有一个引用错误

def closure():
    def inner():
        nonlocal count
        count += 1
        print(count)
    inner()
    count = 0

start = closure()

这里,在定义计数之前调用内部方法

相关问题 更多 >