Python的作用域规则究竟是什么?

如果我有一些代码:

code1
class Foo:
   code2
   def spam.....
      code3
      for code4..:
       code5
       x()

x在哪?一些可能的选择包括以下列表:

在封闭的源文件中 在类名称空间中 在函数定义中 在for循环的索引变量中 在for循环中

还有执行期间的上下文,当函数spam被传递到其他地方时。也许lambda函数传递有点不同?

在某个地方一定有一个简单的参考或算法。对于中级Python程序员来说,这是一个令人困惑的世界。


当前回答

Python 2的作用域规则。X已经在其他答案中概述了。我唯一要补充的是,在Python 3.0中,还有一个非本地作用域的概念(由'nonlocal'关键字表示)。这允许您直接访问外部作用域,并提供了执行一些巧妙技巧的能力,包括词法闭包(没有涉及可变对象的丑陋操作)。

编辑:这里是PEP的更多信息。

其他回答

一个稍微完整一点的范围示例:

from __future__ import print_function  # for python 2 support

x = 100
print("1. Global x:", x)
class Test(object):
    y = x
    print("2. Enclosed y:", y)
    x = x + 1
    print("3. Enclosed x:", x)

    def method(self):
        print("4. Enclosed self.x", self.x)
        print("5. Global x", x)
        try:
            print(y)
        except NameError as e:
            print("6.", e)

    def method_local_ref(self):
        try:
            print(x)
        except UnboundLocalError as e:
            print("7.", e)
        x = 200 # causing 7 because has same name
        print("8. Local x", x)

inst = Test()
inst.method()
inst.method_local_ref()

输出:

1. Global x: 100
2. Enclosed y: 100
3. Enclosed x: 101
4. Enclosed self.x 101
5. Global x 100
6. global name 'y' is not defined
7. local variable 'x' referenced before assignment
8. Local x 200

在Python中,

任何被赋值的变量都是所在块的局部变量 作业出现了。

如果在当前范围内找不到变量,请参考LEGB顺序。

本质上,Python中唯一引入新作用域的是函数定义。类有点特殊,因为在主体中直接定义的任何东西都放在类的名称空间中,但它们不能从它们所包含的方法(或嵌套类)中直接访问。

在你的例子中,只有3个范围x将被搜索:

垃圾邮件的作用域——包含code3和code5(以及循环变量code4)中定义的所有内容 全局作用域——包含代码1中定义的所有内容,以及Foo(以及其后的任何更改) 内置命名空间。有点特殊的情况-它包含各种Python内置函数和类型,如len()和str()。一般来说,任何用户代码都不应该修改它,所以期望它只包含标准函数。

只有在向图中引入嵌套函数(或lambda)时,才会出现更多作用域。 不过,它们的表现和你预期的差不多。嵌套函数可以访问局部作用域中的所有内容,也可以访问封闭函数作用域中的任何内容。如。

def foo():
    x=4
    def bar():
        print x  # Accesses x from foo's scope
    bar()  # Prints 4
    x=5
    bar()  # Prints 5

限制:

可以访问局部函数变量以外的作用域中的变量,但不能在没有进一步语法的情况下反弹到新参数。相反,赋值将创建一个新的局部变量,而不是影响父作用域中的变量。例如:

global_var1 = []
global_var2 = 1

def func():
    # This is OK: It's just accessing, not rebinding
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable
    global_var2 = 2 

    local1 = 4
    def embedded_func():
        # Again, this doen't affect func's local1 variable.  It creates a 
        # new local variable also called local1 instead.
        local1 = 5
        print local1

    embedded_func() # Prints 5
    print local1    # Prints 4

为了从函数作用域中实际修改全局变量的绑定,需要使用global关键字指定变量为全局变量。例如:

global_var = 4
def change_global():
    global global_var
    global_var = global_var + 1

目前还没有办法对封闭函数作用域中的变量做同样的事情,但Python 3引入了一个新的关键字“nonlocal”,它将以类似于global的方式起作用,但用于嵌套函数作用域。

Python 2的作用域规则。X已经在其他答案中概述了。我唯一要补充的是,在Python 3.0中,还有一个非本地作用域的概念(由'nonlocal'关键字表示)。这允许您直接访问外部作用域,并提供了执行一些巧妙技巧的能力,包括词法闭包(没有涉及可变对象的丑陋操作)。

编辑:这里是PEP的更多信息。

实际上,Python作用域解析的一个简明规则,见《学习Python》第3期。Ed . .(这些规则是特定于变量名的,而不是属性。如果你引用它时没有句号,则适用这些规则。)

LEGB规则

Local -在函数(def或lambda)中以任何方式赋值的名称,并且在该函数中未声明为全局的名称 封闭函数——在任何和所有静态封闭函数(def或lambda)的局部作用域内赋值的名称,从内部到外部 Global (module)——在模块文件的顶层赋值的名称,或者通过在文件的def中执行全局语句赋值 内置(Python) -在内置名称模块中预先分配的名称:open, range, SyntaxError等

在这种情况下

code1
class Foo:
    code2
    def spam():
        code3
        for code4:
            code5
            x()

for循环没有自己的名称空间。按照LEGB的顺序,作用域是

L: Local in def spam(在code3, code4,和code5中) E:任何外围函数(如果整个例子在另一个def中) G:在模块中(在代码1中)是否有任何全局声明的x ? B: Python中的任何内置x。

x永远不会在代码2中找到(即使在您可能期望它会出现的情况下,参见Antti的答案或这里)。