跳转到内容

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

关键字 global

[编辑 | 编辑源代码]

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]

链接

关键字 nonlocal

[编辑 | 编辑源代码]

关键字 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()

链接

globals 和 locals

[编辑 | 编辑源代码]

要找出全局作用域和局部作用域中存在哪些变量,可以使用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() 字典进行写操作。

链接

[编辑 | 编辑源代码]
华夏公益教科书