LISTL = [] VAR1 = 0 def foo():… VAR1 += 1… 返回 VAR1…
在调用时foo(),我收到此错误:
foo()
UnboundLocalError: local variable 'VAR1' referenced before assignment
然而,考虑一下LISTL
LISTL
>>> def foo(x): ... LISTL.append(x) ... return LISTL ... >>> foo(5) [5]
这按预期工作。问题是为什么列表上的附加功能有效,但我无法更改 int?
另外,这是在 Python 中声明全局变量的正确方法吗?(紧接着 import 语句)
append
这归结于 Python 的作用域规则 和 数据的可变性。
VAR1
当你尝试在 foo() 中修改全局变量 VAR1 时,Python 会把 VAR1 += 1 当作对一个局部变量的引用和赋值。这是因为 += 本质上是 VAR1 = VAR1 + 1,它会创建一个新的变量并赋值。
VAR1 += 1
+=
VAR1 = VAR1 + 1
global
UnboundLocalError
示例错误:
VAR1 = 0 def foo(): VAR1 += 1 # Python 假定这是一个局部变量 return VAR1
这里会报错,因为 VAR1 被赋值前就被引用了。
与整数不同,LISTL 是一个 可变对象(mutable object)。调用 LISTL.append(x) 修改的是 LISTL 的内容,而不是重新赋值。
LISTL.append(x)
append()
示例:
LISTL = [] def foo(x): LISTL.append(x) # 修改全局列表的内容 return LISTL
这之所以有效,是因为你没有试图覆盖全局变量 LISTL 的引用。
如果你需要在函数中修改全局变量,必须显式声明 global。
修改后的代码:
VAR1 = 0 def foo(): global VAR1 # 显式声明使用全局变量 VAR1 += 1 return VAR1 print(foo()) # 输出 1
global VAR1 告诉 Python,这里的 VAR1 是全局作用域中的变量,而不是函数内部的新局部变量。
global VAR1
将全局变量直接放在文件的顶部、紧随 import 语句之后是可以接受的做法。然而,大量使用全局变量通常不是推荐的做法,因为它可能会导致以下问题: 1. 降低代码的可读性:不清楚变量可能被哪些地方修改。 2. 增加调试难度:全局状态可以在代码中的任何地方被更改。 3. 影响模块化:全局变量会破坏代码的封装性和可复用性。
import
使用函数参数和返回值传递和修改数据,而不是依赖全局变量。
def foo(var1): var1 += 1 return var1 VAR1 = 0 VAR1 = foo(VAR1) # 更新 VAR1 print(VAR1) # 输出 1
将全局状态封装在类中,既可以保持状态,也可以避免使用全局变量。
class Counter: def __init__(self): self.var1 = 0 def increment(self): self.var1 += 1 return self.var1 counter = Counter() print(counter.increment()) # 输出 1 print(counter.increment()) # 输出 2
functools.partial
利用闭包或 functools.partial 来保存状态,而不是依赖全局变量。
def make_counter(): var1 = 0 def counter(): nonlocal var1 # 声明非局部变量 var1 += 1 return var1 return counter foo = make_counter() print(foo()) # 输出 1 print(foo()) # 输出 2
整数是不可变对象,修改它实际上会创建一个新对象,因此需要显式声明 global。
如何正确修改全局变量?
使用 global 声明全局变量。
推荐做法: