You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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的作用域查找规则可以简单总结为:

  1. 当你在函数内部读取一个变量时:Python会先在当前函数的局部作用域里找,如果找不到,就会一层层往上找(比如全局作用域、内置作用域),直到找到为止。
  2. 当你在函数内部对变量进行赋值(包括+=这种增量赋值,本质是「先读旧值→计算新值→赋值」的组合操作)时: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

火山引擎 最新活动