确定 import * 和 from xxx import * 的区别

15

我很惊讶地发现

import foo
并且
from foo import *

对全局成员产生不同的影响。我想确认我的实验是否是正确的行为。

在第一个例子中,更改模块foo中的成员将反映在导入foo的所有代码中。然而,在后一种情况下更改该成员似乎只会影响导入它的文件。换句话说,使用后一种方法将使每个导入文件都拥有自己的foo成员副本。

我的期望行为是能够从所有文件访问foo.x,能够在所有文件中更改它,并且让这些更改在所有文件中反映出来(如果你愿意,这是真正的全局变量)。

2个回答

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中最接近真正全局的一种方式。作为一门语言,它非常重视命名空间。


4

考虑到全局变量通常被认为是不好的事情,我怀疑“真正的全局”变量将是一件极其糟糕的事情。

获取类似行为的另一种方法是在单例对象中使用类作用域属性,然后只需导入它。这样就清楚了你从哪里获取“全局”变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接