Python的作用域规则究竟是什么?
如果我有一些代码:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
x在哪?一些可能的选择包括以下列表:
在封闭的源文件中
在类名称空间中
在函数定义中
在for循环的索引变量中
在for循环中
还有执行期间的上下文,当函数spam被传递到其他地方时。也许lambda函数传递有点不同?
在某个地方一定有一个简单的参考或算法。对于中级Python程序员来说,这是一个令人困惑的世界。
一个稍微完整一点的范围示例:
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中唯一引入新作用域的是函数定义。类有点特殊,因为在主体中直接定义的任何东西都放在类的名称空间中,但它们不能从它们所包含的方法(或嵌套类)中直接访问。
在你的例子中,只有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作用域解析的一个简明规则,见《学习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的答案或这里)。