在 Python 中,函数是否捕获定义函数后创建的变量?

In Python, does a function capture variables created after the function is defined?

提问人:master_latch 提问时间:3/11/2023 更新时间:3/11/2023 访问量:68

问:

我试图更好地理解闭包。根据我的理解,示例 1 - 3 对我来说是有意义的,但我认为它一定是不正确的,因为示例 4 对我来说没有意义。

示例 1

def f():
    print(x)
x=1
f() # prints 1

当时定义,不存在,但没关系。它将在被调用时被查找,此时存在。f()xf()x

示例 2

y=2
def g():
    print(y)
g() # prints 2

这是一个结束。何时定义、存在并捕获对它的引用。如果我要更改 after defined 的值,则在调用时将反映此更改。据我所知,这不涉及关闭。g()yg()yg()g()

示例 3

def h():
    x=3
    def i():
        print(x)
    return i
j=h()
j() # prints 3

这仅表明,即使在变量超出范围后,闭包仍保留对变量的引用。一旦返回,我就不能直接引用,因为它已经超出了范围,但保留了对它的引用。h()xj()

示例 4

def k():
    def l():
        print(x)
    x=4
    return l
m=k()
m() # prints 4

这让我感到困惑。我认为(正如我在示例 1 中声称的那样)这不是一个闭包,因此它不保留对 ;它只是在调用时尝试查找。但是,事实上,当我们通过 调用它时,即使它已经超出了范围,也会被打印出来。这是否意味着示例 1 中也是一个闭包?令人惊讶的是,一个函数可以捕获在其定义后创建的变量。除非说它捕获变量本身是错误的。说它捕获了定义它的“环境”或“范围”是否更准确?l()xxm()xf()

Python 闭包

评论

2赞 quamrana 3/11/2023
这个 YouTube 视频解释了一切mCoding
0赞 trincot 3/11/2023
“这是否意味着示例 1 中的 f() 也是一个闭包?”:是的
1赞 master_latch 3/11/2023
@quamrana 哦,哇,在“级别 2”部分,他解释说,即使在未执行的代码路径中,也要分配给变量,也会更改查找的变量,这让我大吃一惊,这是理解这一点的关键。谢谢。
0赞 user19077881 3/11/2023
pythontutor 非常适合展示此类代码片段的工作原理;只需粘贴代码并可视化分步链接

答:

1赞 rv.kvetch 3/11/2023 #1

根据问题:

def k():
    def l():
        print(x)
    x=4
    return l
m=k()
m() # prints 4

嵌套函数可以访问外部函数局部变量。在本例中,是函数的局部变量。因此,内部功能也可以访问相同的信息。x=4k()l()

进一步研究:我建议启动 REPL 并在终端窗口中尝试一下。python

>>> def k():
...   a = 1
...   def l():
...     print(a, b)
...     print(locals())
...   b = 2
...   print(locals())
...   return l
... 
>>> k()
{'l': <function k.<locals>.l at 0x10140bec0>, 'a': 1, 'b': 2}
<function k.<locals>.l at 0x10140bec0>
>>> k()()
{'l': <function k.<locals>.l at 0x101414180>, 'a': 1, 'b': 2}
1 2
{'a': 1, 'b': 2}

希望这会有所帮助。

评论

0赞 master_latch 3/11/2023
嵌套函数可以访问外部函数的局部变量这一事实并不是让我感到困惑的部分(这只是一个直接的闭包,如我的示例 3 所示)。让我感到困惑的是,它甚至可以访问在定义内部函数之后定义的变量。但是 OP 上的一条评论中链接的 mCoding 视频清楚地解释了这一点。
0赞 rv.kvetch 3/11/2023
@master_latch我不确定我是否理解混乱在哪里。在哪个点定义函数(在变量之前或之后)定义函数并不重要。真正重要的是在什么范围(级别)上,在它被调用的时候,它可以访问这些变量(如果你考虑一下,这是有道理的)。