Python全局变量异常行为疑问:未声明global的s2为何可正常使用?
为什么修改全局变量
cpt需要global,而读取s2不需要? 好问题!这其实戳中了Python作用域规则里一个很关键的细节,咱们结合你的代码来拆解清楚:
首先先回顾你的场景:
错误代码(cpt报错):
s2 = 'prefixe' cpt = 1 def test(): cpt += 1 str = "%s%d" % (s2,cpt) print(str) test()
修正后代码(正常运行):
s2 = 'prefixe' cpt = 1 def test(): global cpt cpt += 1 str = "%s%d" % (s2,cpt) print(str) test()
核心原因:Python对「读取变量」和「赋值/修改变量」的处理逻辑完全不同
Python的作用域查找规则可以简单总结为:
- 当你在函数内部读取一个变量时:Python会先在当前函数的局部作用域里找,如果找不到,就会一层层往上找(比如全局作用域、内置作用域),直到找到为止。
- 当你在函数内部对变量进行赋值(包括
+=这种增量赋值,本质是「先读旧值→计算新值→赋值」的组合操作)时:Python会默认把这个变量当成局部变量,哪怕全局作用域里已经有同名变量。这时候如果你在赋值前先读取了它(比如cpt +=1需要先拿cpt的当前值),就会触发「变量在赋值前被读取」的错误。
对应到你的代码:
- 对于
cpt:你在函数里写了cpt +=1,这属于「修改+赋值」操作,Python会默认把cpt当作局部变量,但你并没有在函数内部先定义这个局部变量,直接就去读它的值来做增量操作,自然就报错了。加上global cpt声明后,Python就明白:“哦,这个cpt是全局作用域里的那个,我要去全局找它并修改”,所以就正常运行了。 - 对于
s2:你在函数里只是把它的值拿来格式化字符串,全程没有对s2做任何赋值/修改操作,所以Python会自动按照作用域查找规则,去全局作用域找到s2并读取它的值,完全不需要额外声明global。
补充个反例加深理解
如果我们尝试在函数里给s2赋值,情况就不一样了:
s2 = 'prefixe' def test(): s2 = 'new_prefix' # 这里会创建一个局部的s2,和全局的s2无关 print(s2) test() print(s2) # 输出还是'prefixe',全局s2没被修改
如果想真正修改全局的s2,同样需要global声明:
s2 = 'prefixe' def test(): global s2 s2 = 'new_prefix' print(s2) test() print(s2) # 输出'new_prefix',全局s2被修改了
总结一下:
- 只读取全局变量:不用加
global,Python会自动向上找。 - 要修改/赋值全局变量:必须加
global声明,否则Python会把变量当成局部的,导致错误。
内容的提问来源于stack exchange,提问作者Bob5421




