我很惊讶地发现
import foo
并且from foo import *
对全局成员产生不同的影响。我想确认我的实验是否是正确的行为。
在第一个例子中,更改模块foo中的成员将反映在导入foo的所有代码中。然而,在后一种情况下更改该成员似乎只会影响导入它的文件。换句话说,使用后一种方法将使每个导入文件都拥有自己的foo成员副本。
我的期望行为是能够从所有文件访问foo.x,能够在所有文件中更改它,并且让这些更改在所有文件中反映出来(如果你愿意,这是真正的全局变量)。
我很惊讶地发现
import foo
并且from foo import *
对全局成员产生不同的影响。我想确认我的实验是否是正确的行为。
在第一个例子中,更改模块foo中的成员将反映在导入foo的所有代码中。然而,在后一种情况下更改该成员似乎只会影响导入它的文件。换句话说,使用后一种方法将使每个导入文件都拥有自己的foo成员副本。
我的期望行为是能够从所有文件访问foo.x,能够在所有文件中更改它,并且让这些更改在所有文件中反映出来(如果你愿意,这是真正的全局变量)。
是的,你的观察是正确的。这是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中最接近真正全局的一种方式。作为一门语言,它非常重视命名空间。
考虑到全局变量通常被认为是不好的事情,我怀疑“真正的全局”变量将是一件极其糟糕的事情。
获取类似行为的另一种方法是在单例对象中使用类作用域属性,然后只需导入它。这样就清楚了你从哪里获取“全局”变量。