Python全局变量和局部变量

5 投票
2 回答
722 浏览
提问于 2025-04-17 20:06

在Python 2.7中,运行以下代码:

def f():
    a = a + 1

f()

会得到以下结果:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    f()
  File "test.py", line 2, in f
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

但是如果我把代码改成下面这样:

def f():
    a[0] = a[0] + 1

f()

我就会遇到不同的错误:

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    f()
  File "test.py", line 2, in f
    a[0] = a[0] + 1
NameError: global name 'a' is not defined

为什么Python在处理a时把它当作局部变量,而在处理list时又把它当作全局变量呢?这背后有什么原因吗?

附注:我是在阅读这个讨论后进行实验的。

2 个回答

-1

你能试着做类似这样的事情吗:

def f(a):
    a += 1
    print a

def g():
    a = 3
    f(a)

g()
7

关键在于文档中关于 赋值语句 的说明:

将一个对象赋值给一个目标的过程可以递归地定义如下。

如果目标是一个标识符(名字)(例如 a = a + 1)

  • 如果这个名字在当前代码块中没有出现在全局声明中:这个名字会绑定到当前本地命名空间中的对象。
  • 否则:这个名字会绑定到当前全局命名空间中的对象。

如果这个名字之前已经绑定过,那么它会被重新绑定。这可能会导致之前绑定到这个名字的对象的引用计数变为零,从而使这个对象被释放,并调用它的析构函数(如果有的话)。

...

如果目标是一个下标(例如 a[0] = a[0] + 1):首先会计算引用中的主要表达式。这个表达式应该返回一个可变的序列对象(比如列表)或者一个映射对象(比如字典)。接下来,会计算下标表达式。

f1 中,Python 看到你正在给 a 绑定一个值,发现 a 在这个范围内没有出现在 global a 声明中,于是准备了一个本地变量。然后它尝试计算表达式 a + 1,查找变量 a,结果发现是一个未初始化的本地变量。这就导致了 UnboundLocalError 错误。

f2 中,Python 看到你正在给变量 a 的一个下标赋值。它在本地命名空间中查找这个变量,但没有找到。然后它会向上查找非本地命名空间(闭包),直到找到全局命名空间。一旦在全局命名空间中也找不到 a,就会抛出 NameError 错误。

撰写回答