11

我试图了解,python 中的变量绑定究竟是如何工作的。让我们看看这个:

def foo(x):
    def bar():
        print y
    return bar

y = 5
bar = foo(2)
bar()

这打印出 5,这对我来说似乎是合理的。

def foo(x):
    def bar():
        print x
    return bar
x = 5
bar = foo(2)
bar()

这会打印 2,这很奇怪。在第一个示例中,python 在执行期间查找变量,第二个示例在创建方法时查找。为什么会这样?

需要明确的是:这非常酷,并且完全按照我的意愿工作。但是,我对内部 bar 函数如何获取其上下文感到困惑。我想了解,引擎盖下会发生什么。

编辑

我知道,局部变量具有更高的优先级。我很好奇,python 在执行过程中如何知道从我之前调用的函数中获取参数。bar已在其中创建foo并且x不再存在。它在创建函数时已将 this 绑定x到参数值?

4

5 回答 5

7

第二个示例实现了所谓的闭包。该函数从其周围的上下文bar中引用变量,即函数。这在对全局变量的引用之前。xfoox

另见这个问题你能解释闭包(因为它们与 Python 相关)吗?

于 2010-11-27T15:23:46.390 回答
7

您所暗示的问题是python中变量的词法与动态范围之一。明确地说,python 定义了以下四个范围。

  1. 首先搜索的最内层范围包含本地名称
  2. 从最近的封闭范围开始搜索的任何封闭函数的范围都包含非本地名称,但也包含非全局名称
  3. 倒数第二个范围包含当前模块的全局名称
  4. 最外层范围(最后搜索)是包含内置名称的命名空间

在第一个示例中,“y”定义在函数栏之外,python 搜索最里面的范围并向上移动,直到在模块中找到全局变量“y”

在第二个示例中,“x”由函数 foo(x) 定义,当 x 被打印在 bar 内时,它属于封闭函数的范围。在纯粹的术语中,已经定义了一个闭包。

为了进一步研究 python 中的作用域,我发现以下文章非常适合阅读

于 2010-11-27T15:25:11.300 回答
1

在这两个示例中,查找都发生在运行时。唯一的区别是有一个本地定义的变量x,而没有一个本地定义的变量y

执行时...

def foo(x):
    def bar():
        print y

    return bar

y = 5
bar = foo(2)
bar()

...该print语句查找名为 的变量y,并且仅在全局上下文中找到它,因此它使用该变量并打印“5”。

在 ...

def foo(x):
    def bar():
        print x

    return bar

x = 5
bar = foo(2)
bar()

...当查找发生时,定义了一个作用域变量——当函数被调用 x时,它被固定为“5” 。foo

关键是参数在传递给函数时被评估,因此外部函数foo在调用时评估传入的参数。这有效地创建了一个x在函数上下文中调用的变量foo,因此无论何时bar执行它都会看到该变量,而不是全局定义的变量。

这有时会令人困惑,如以下代码所示:

lst = []
for i in range(5):
    x = i
    lst.append(lambda: x)

for func in lst:
    print func()  # prints 4 4 4 4 4

你需要做:

lst = []
for i in range(5):
    def _func(x):
        return lambda: x

    lst.append(_func(i))

for func in lst:
    print func()  # prints 0 1 2 3 4
于 2010-11-27T15:25:33.593 回答
0

没什么奇怪的,这是因为函数参数中的“x”比全局变量“x”具有更高的优先级。

起初,全局变量是个大恶。

Python 有运算符“全局”:

>>> def foo(x):
...     def bar():
...          global x
...          print x
...     return bar
... 
>>> x = 5
>>> bar = foo(2)
>>> bar()
5
于 2010-11-27T15:18:17.873 回答
0

它是作用域的主体,第二个示例使用局部作用域变量x,在上面全局声明之前

于 2010-11-27T15:18:59.000 回答