变量

在 Python 中,变量是通过赋值自动声明的。变量总是引用对象,并且永远没有型。变量仅存在于当前作用域或全局作用域。当它们超出作用域时,变量会被销毁,但它们引用的对象不会(除非引用该对象的次数降为零)。

作用域由函数块来划定。函数和它们的作用域可以是嵌套的。因此,以下代码是有效的:

def foo():
    def bar():
        x = 5  # x现在在作用域内
        return x + y  # y在后续的外部作用域中定义
    y = 10
    return bar()  # 当y被定义时,bar的作用域包括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 是列表的一个方法

错误提示:

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,而不是错误

global 关键字

Python 模块中的全局变量可以被该模块中的函数读取。如果它们是可变的,还可以通过方法调用进行修改。然而,除非在函数中声明为 global,否则不能通过直接赋值来修改它们。

例如:

count1 = 1
count2 = 1
list1 = []
list2 = []

def test1():
  print(count1)  # 读取访问没有问题,引用全局变量

def test2():
  try:
    print(count1)  # 这个 try 块有问题...
    count1 += 1  # count1 += 1 会让 count1 成为局部变量,但局部变量没有定义。
  except UnboundLocalError as error:
    print("Error caught:", error)

def test3():
  list1 = [2]  # 不影响外部;这将 list1 定义为局部变量

def test4():
  global count2, list2
  print(count1)  # 读取访问没有问题,引用全局变量
  count2 += 1    # 通过赋值修改 count2
  list1.append(1)  # 影响全局的 list1,即使没有 global 声明,因为它是方法调用
  list2 = [2]   # 通过赋值修改 list2

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 关键字的似物,用于嵌套作用域。它允许嵌套函数修改外部函数中的不可变变量。

例如:

# 需要 Python 3
def outer():
  outerint = 0
  outerint2 = 10
  def inner():
    nonlocal outerint
    outerint = 1  # 只有通过 nonlocal 声明,才能影响外部的 outerint
    outerint2 = 1  # 没有影响
  inner()
  print(outerint)  # 输出 1
  print(outerint2) # 输出 10

outer()

如果在 Python 2 中模拟 nonlocal,可以通过可变对象实现:

def outer():
  outerint = [1]  # 技巧1:将整数存储在列表中
  class outerNL: pass  # 技巧2:将整数存储在中
  outerNL.outerint2 = 11
  def inner():
    outerint[0] = 2  # 可以修改列表成员
    outerNL.outerint2 = 12  # 可以修改成员
  inner()
  print(outerint[0])  # 输出 2
  print(outerNL.outerint2)  # 输出 12

outer()

globals 和 locals

要找出在全局和局部作用域中存在哪些变量,可以使用 locals()globals() 函数,它们返回字典:

int1 = 1
def test1():
  int1 = 2
  globals()["int1"] = 3  # 写入访问似乎是可能的
  print(locals()["int1"])  # 输出 2

test1()

print(int1)  # 输出 3

Python 文档不建议对 locals() 字典进行写入操作。

【链接】:

最后修改: 2025年01月31日 星期五 00:22