Python:绑定是如何工作的

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不再存在。它绑定了该x到函数创建时的参数值吗?
5个回答

7

这个链接解释得非常好。非常感谢。 - gruszczy

7
你提到的问题涉及python中变量的词法和动态作用域。具体来说,python定义了以下四个作用域:
  1. 最内层作用域首先被搜索,包含局部名称
  2. 任何封闭函数的作用域,从最近的封闭作用域开始搜索,包含非全局但也非本地的名称
  3. 倒数第二个作用域包含当前模块的全局名称
  4. 最外层作用域(最后搜索)是包含内置名称的命名空间
在第一个例子中,“y”在函数bar之外定义,python搜索了最内层作用域并向上移动到模块中找到全局变量“y”。
在第二个例子中,当函数foo(x)定义x时,x属于封闭函数的作用域,在bar中打印时使用。严格意义上讲,已经定义了一个闭包。
如需深入研究python中的作用域,请参考以下文章

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--在调用foo函数时固定为"5"。

关键在于参数在传入函数时被评估,因此外部函数foo在调用时评估传入的参数。这实际上在foo函数的上下文中创建了一个名为x的变量,因此每当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

0

这是作用域的问题,第二个例子使用了局部作用域变量x,该变量在全局声明之前被声明。


0

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

首先,全局变量是一个巨大的恶魔。

Python 有一个“global”运算符:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接