确认 import * 和 from xxx import * 之间的区别

15 投票
2 回答
4033 浏览
提问于 2025-04-16 08:30

我很惊讶地发现

import foo

from foo import *

对全局变量的影响是不同的。我想确认一下我的实验结果是否正确。

在第一个例子中,修改模块 foo 中的一个成员会在所有导入了 foo 的代码中反映出来。然而,在后面的例子中,修改这个成员似乎只影响了导入它的那个文件。换句话说,使用后面的方法会让每个导入的文件都有自己的一份 foo 的成员。

我想要的行为是,能够从所有文件访问 foo.x,能够从所有文件修改它,并且这个修改能在所有文件中反映出来(也就是说,真正的全局变量)。

2 个回答

4

大家都知道,全局变量通常被认为是不好的东西,所以我觉得“真正的全局”变量会更糟糕。

还有一种方法可以实现类似的效果,就是在一个单例对象中使用类作用域的属性,然后直接导入这个对象。这样就更清楚你是从哪里获取这个“全局”变量的。

16

是的,你的观察是正确的。这是因为Python中的绑定方式所导致的结果。

当你执行

import foo

时,foo就变成了一个全局名称,指向模块foo。当你执行

foo.bar = 7

时,系统会找到这个引用并加载对象foo。然后,7就被存储在bar这个属性里。

当其他模块导入foo时,它只是从sys.modules['foo']中提取这个对象,并获取到修改后的值。

当你执行

from foo import bar

globals()['bar']被设置为引用foo.bar。但当你之后执行

 bar = 7

globals()['bar']就不再指向foo.bar,而是指向了7的一个副本。也就是说,导入模块的全局范围内的原始绑定被简单地替换掉了。

在第一个例子中,你是在修改一个存储在sys.modules中的对象的属性,这个对象对所有导入它的模块都是共享的。而在第二个例子中,你是在修改导入模块的全局范围。

如果你做类似于

 from foo import fobaz
 fobaz.foobar = 7

的事情,那么这个改变传播到其他导入的模块,因为你并没有覆盖全局引用,而是跟随它去修改它指向的对象的属性。所以,基本上,只要你不覆盖全局绑定,你就可以修改可变对象。

我认为,这种方式是你在Python中最接近实现真正全局变量的方式。作为一种语言,Python非常重视命名空间。

撰写回答