全局变量赋值后ID变更,为何未保持全局特性?
全局变量赋值后ID变化的疑惑
先看我写的代码:
初始全局变量定义:
ex = False orig = id(ex)
两个测试函数:
def start(test): print("Start") global ex while True: if id(ex) == orig: print("same") else: print(orig) print(id(ex)) def end(test): print("End") global ex ex = True while True: if id(ex) == orig: print("same") else: print(orig) print(id(ex))
调用end函数时,里面的ex的ID和初始的orig完全不一样,但注释掉ex = True这行后,ID就和orig一致了。我本来以为global关键字的作用就是允许在函数里修改全局变量,实在搞不懂为什么赋值后ID会变。
问题本质解释
首先得搞清楚两个关键点:
global关键字的作用:它是告诉Python,函数里的ex这个名字指向的是全局作用域里的变量,而不是创建一个局部的ex变量。它允许你修改全局变量的绑定关系,而不是修改变量指向的对象本身。- Python的不可变对象特性:
False和True都是不可变的布尔对象,而且Python会把它们做成单例——也就是说,整个程序里False只有一个实例,True也只有一个实例。
初始时,全局变量ex绑定的是False的实例,orig记录的就是这个实例的内存ID。当你执行ex = True时,并不是把原来的False对象改成True(不可变对象根本没法修改),而是把全局变量ex的绑定关系改了——让它指向True的实例。这时候id(ex)自然就是True实例的ID,和原来的orig肯定不一样。
如果是可变对象(比如列表),情况就不同:比如你定义ex = [],然后在函数里用global ex,再执行ex.append(1),这时候ex的ID不会变,因为你只是修改了列表对象内部的内容,没有改变ex的绑定关系——它还是指向原来那个列表实例。
关于函数中使用全局变量的补充说明
- 若只是在函数内读取全局变量,不需要
global关键字,Python会自动优先在局部作用域查找,找不到就去全局作用域找。 - 若要在函数内给全局变量重新赋值(改变它指向的对象),必须用
global声明,否则Python会把这个变量当作局部变量,执行时会报错(比如未赋值就引用)。 - 对于可变对象,仅修改其内部元素(比如列表追加、字典改值)时,不需要
global,因为这没有改变变量的绑定,只是修改了对象本身。
内容的提问来源于Stack Exchange,提问作者Skobo Do
相关产品推荐
相关产品推荐

