带有导入的全局变量

35 投票
3 回答
27302 浏览
提问于 2025-04-16 10:03

first.py

myGlobal = "hello"

def changeGlobal():
   myGlobal="bye"

second.py

from first import *

changeGlobal()
print myGlobal

我得到的输出是

hello

虽然我原以为应该是

bye

为什么在调用 changeGlobal() 函数后,全局变量 myGlobal 没有改变呢?

3 个回答

2

Python中的全局变量并不是真正的全局变量

正如wassimans上面提到的,这些变量实际上是在它们被定义的模块范围内的属性(或者是定义它们的函数所在的模块)。

人们首先会遇到的困惑(问题)是,他们没有意识到函数有自己的局部命名空间。在函数内部设置一个变量时,这个变量就变成了函数的局部变量,即使他们本来是想改变一个在外部模块中同名的全局变量。(在函数中用'global'声明这个名字,或者在设置之前访问这个全局变量。)

第二个困惑(问题)是,每个模块(也就是导入的文件)都有自己的所谓“全局”命名空间。我想Python认为世界(地球)就是模块——也许我们在寻找的是跨越多个地球的“通用”变量。

第三个困惑(我现在开始理解的)是,__main__模块中的“全局变量”在哪里?也就是说,如果你在命令行中以交互模式启动Python,或者你运行一个Python脚本(在命令行中输入foo.py的名字)——就没有导入任何可以使用的模块。

通过'globals()'或globals().keys()可以获取全局变量的列表,这似乎可以通过以下方式访问:dir(sys.modules['__main__'])。看起来,对于加载的Python脚本(或者没有加载脚本的交互会话),在__name__中命名的模块没有全局名称,但在系统的所有活动模块列表sys.modules中可以作为名为'__main__'的模块访问。

8

我曾经也有过和你一样的疑问,读了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()来实现。假设AB中导入了所有内容,那么A将获得一个名为GetX()的函数,这个函数是B中同名函数的副本,唯一的目的是返回X的值。除非B更改了这个函数(这是可能的,比如函数可以被重新赋值),否则两个模块中的函数将始终相同,因此A可以使用它的函数来获取B中X的值。

23

试试这个:

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"

撰写回答