Python 编程/作用域
外观
Python 中的变量通过赋值自动声明。变量始终是对对象的引用,并且永远不会被类型化。变量仅存在于当前作用域或全局作用域中。当它们超出作用域时,变量会被销毁,但它们引用的对象不会(除非对该对象的引用数量降至零)。
作用域由函数和类块定义。函数及其作用域都可以嵌套。因此
def foo():
def bar():
x = 5 # x is now in scope
return x + y # y is defined in the enclosing scope later
y = 10
return bar() # now that y is defined, bar's scope includes y
现在测试这段代码时,
>>> foo()
15
>>> bar()
Traceback (most recent call last):
File "<pyshell#26>", line 1, in -toplevel-
bar()
NameError: name 'bar' is not defined
找不到名称“bar”,因为较高级别的作用域无法访问层次结构中较低级别的名称。
在使用之前没有将对象分配给变量是一个常见的陷阱。最常见的形式是
>>> for x in range(10):
y.append(x) # append is an attribute of lists
Traceback (most recent call last):
File "<pyshell#46>", line 2, in -toplevel-
y.append(x)
NameError: name 'y' is not defined
在这里,要纠正此问题,必须在 for 循环执行之前添加 y = []。
循环不会创建自己的作用域
for x in [1, 2, 3]:
inner = x
print(inner) # 3 rather than an error
Python 模块的全局变量可以从该模块中的函数中读取。实际上,如果它们是可变的,它们也可以通过方法调用进行修改。但是,除非在函数中声明为global,否则它们不能通过简单的赋值进行修改。
一个例子来澄清
count1 = 1
count2 = 1
list1 = []
list2 = []
def test1():
print(count1) # Read access is unproblematic, referring to the global
def test2():
try:
print(count1) # This try block is problematic because...
count1 += 1 # count1 += 1 causes count1 to be local but local version is undefined.
except UnboundLocalError as error:
print("Error caught:", error)
def test3():
list1 = [2] # No outside effect; this defines list1 to be a local variable
def test4():
global count2, list2
print(count1) # Read access is unproblematic, referring to the global
count2 += 1 # We can modify count2 via assignment
list1.append(1) # Impacts the global list1 even without global declaration since its a method call
list2 = [2] # We can modify list2 via assignment
test1()
test2()
test3()
test4()
print("count1:", count1) # 1
print("count2:", count2) # 2
print("list1:", list1) # [1]
print("list2:", list2) # [2]
链接
- 6.13. The global statement,docs.python.org
- Python 中局部变量和全局变量的规则是什么? 在编程常见问题解答中,docs.python.org
关键字 nonlocal,从 Python 3.0 开始可用,是global 在嵌套作用域中的类似物。它使嵌套函数能够分配修改甚至是外部函数中局部的不可变变量。
一个例子
# Requires Python 3
def outer():
outerint = 0
outerint2 = 10
def inner():
nonlocal outerint
outerint = 1 # Impacts outer's outerint only because of the nonlocal declaration
outerint2 = 1 # No impact
inner()
print(outerint)
print(outerint2)
outer()
Python 2 中使用可变对象模拟 nonlocal
def outer():
outerint = [1] # Technique 1: Store int in a list
class outerNL: pass # Technique 2: Store int in a class
outerNL.outerint2 = 11
def inner():
outerint[0] = 2 # List members can be modified
outerNL.outerint2 = 12 # Class members can be modified
inner()
print(outerint[0])
print(outerNL.outerint2)
outer()
链接
- 7.13. The nonlocal statement,docs.python.org
要找出全局作用域和局部作用域中存在哪些变量,可以使用locals() 和globals() 函数,它们返回字典
int1 = 1
def test1():
int1 = 2
globals()["int1"] = 3 # Write access seems possible
print(locals()["int1"])# 2
test1()
print(int1) # 3
Python 文档建议不要对 locals() 字典进行写操作。
链接
- 2. 内置函数 # globals,docs.python.org
- 2. 内置函数 # locals,docs.python.org
- 4. 执行模型,docs.python.org
- 7.13. The nonlocal statement,docs.python.org
- PEP 3104 -- 访问外部作用域中的名称,python.org