带有导入的全局变量
first.py
myGlobal = "hello"
def changeGlobal():
myGlobal="bye"
second.py
from first import *
changeGlobal()
print myGlobal
我得到的输出是
hello
虽然我原以为应该是
bye
为什么在调用 changeGlobal()
函数后,全局变量 myGlobal
没有改变呢?
3 个回答
Python中的全局变量并不是真正的全局变量
正如wassimans上面提到的,这些变量实际上是在它们被定义的模块范围内的属性(或者是定义它们的函数所在的模块)。
人们首先会遇到的困惑(问题)是,他们没有意识到函数有自己的局部命名空间。在函数内部设置一个变量时,这个变量就变成了函数的局部变量,即使他们本来是想改变一个在外部模块中同名的全局变量。(在函数中用'global'声明这个名字,或者在设置之前访问这个全局变量。)
第二个困惑(问题)是,每个模块(也就是导入的文件)都有自己的所谓“全局”命名空间。我想Python认为世界(地球)就是模块——也许我们在寻找的是跨越多个地球的“通用”变量。
第三个困惑(我现在开始理解的)是,__main__
模块中的“全局变量”在哪里?也就是说,如果你在命令行中以交互模式启动Python,或者你运行一个Python脚本(在命令行中输入foo.py的名字)——就没有导入任何可以使用的模块。
通过'globals()'或globals().keys()可以获取全局变量的列表,这似乎可以通过以下方式访问:dir(sys.modules['__main__
'])。看起来,对于加载的Python脚本(或者没有加载脚本的交互会话),在__name__
中命名的模块没有全局名称,但在系统的所有活动模块列表sys.modules中可以作为名为'__main__
'的模块访问。
我曾经也有过和你一样的疑问,读了Norman Matloff的快速简单的Python教程中的以下内容,真的帮了我不少。这里有一些你需要理解的内容(摘自Matloff的书):
Python并不像C/C++那样真正支持全局变量。一个被导入的Python模块无法直接访问导入它的模块中的全局变量,反之亦然。
举个例子,考虑这两个文件,x.py:
# x.py
import y
def f():
global x
x = 6
def main():
global x
x = 3
f()
y.g()
if __name__ == ’__main__’:
main()
和y.py:
# y.py
def g():
global x
x += 1
在x.py中的变量x在整个模块x.py中都是可见的,但在y.py中不可见。实际上,在y.py中执行这一行代码
x += 1会出现错误信息:“全局名称'x'未定义。”
实际上,模块中的全局变量只是该模块的一个属性(也就是一个成员),类似于类变量在类中的作用。当模块B被模块A导入时,B的命名空间会被复制到A中。如果模块B有一个全局变量X,那么模块A会创建一个同名的变量,其初始值是模块B在导入时该变量的值。但是在一个模块中对X的更改不会反映到另一个模块中。
假设B中的X发生了变化,但我们希望A中的代码能够获取B中X的最新值。我们可以通过在B中包含一个函数,比如叫GetX()来实现。假设A从B中导入了所有内容,那么A将获得一个名为GetX()的函数,这个函数是B中同名函数的副本,唯一的目的是返回X的值。除非B更改了这个函数(这是可能的,比如函数可以被重新赋值),否则两个模块中的函数将始终相同,因此A可以使用它的函数来获取B中X的值。
试试这个:
def changeGlobal():
global myGlobal
myGlobal = "bye"
其实,这个也不行。当你使用 import *
的时候,你会创建一个新的 局部 模块全局变量 myGlobal
,这个变量不会受到你想要的改变影响(只要你没有去修改这个变量,下面会解释)。你可以用这个来代替:
import nice
nice.changeGlobal()
print nice.myGlobal
或者:
myGlobal = "hello"
def changeGlobal():
global myGlobal
myGlobal="bye"
changeGlobal()
不过,如果你的全局变量是一个可变的容器,那你现在就持有了一个对这个可变对象的引用,这样你就能看到对它所做的改变:
myGlobal = ["hello"]
def changeGlobal():
myGlobal[0] = "bye"