确认 import * 和 from xxx import * 之间的区别
我很惊讶地发现
import foo
和
from foo import *
对全局变量的影响是不同的。我想确认一下我的实验结果是否正确。
在第一个例子中,修改模块 foo 中的一个成员会在所有导入了 foo 的代码中反映出来。然而,在后面的例子中,修改这个成员似乎只影响了导入它的那个文件。换句话说,使用后面的方法会让每个导入的文件都有自己的一份 foo 的成员。
我想要的行为是,能够从所有文件访问 foo.x,能够从所有文件修改它,并且这个修改能在所有文件中反映出来(也就是说,真正的全局变量)。
2 个回答
大家都知道,全局变量通常被认为是不好的东西,所以我觉得“真正的全局”变量会更糟糕。
还有一种方法可以实现类似的效果,就是在一个单例对象中使用类作用域的属性,然后直接导入这个对象。这样就更清楚你是从哪里获取这个“全局”变量的。
是的,你的观察是正确的。这是因为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非常重视命名空间。