Python导入星号创建隐藏命名空间?

6

我最近遇到了一些不寻常的行为。

foo.py

a = 0
def bar():
    print (a)

控制台:

>>> import foo
>>> foo.bar()
0
>>> foo.a = 10
>>> foo.bar()
10

控制台:

>>> from foo import *
>>> bar()
0
>>> a
0
>>> a = 10
>>> a
10
>>> bar()
0

我推测 import * 实际上会创建两个 a 的副本 - 一个在全局命名空间中,另一个在 foo 模块内部,无法访问。这种行为有没有被解释或记录在哪里?我很难找到相关的搜索结果。
这似乎是 import * 的一个值得注意且意外的后果,但出于某种原因,我从未见过有人提到它。

3
这是一种明确定义的行为,没有隐藏的命名空间,每个函数只是知道其模块全局变量的信息。当前模块中的全局变量不会影响导入模块的全局变量。每个模块都有自己的私有符号表,它被用作模块内所有函数的全局符号表。因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量意外冲突。 - Ashwini Chaudhary
在Python中,本质上并不存在用户定义的全局变量。有一种令人讨厌的黑科技可以创建真正的全局变量,但你基本上永远不应该使用它,而像 a = 10 这样定义的东西最多也只是在模块级别。 - user2357112
@user65 是的,这就是为什么通常认为 import * 是一个不好的想法。 - MattDMo
2
@user65 没错,但这并不意味着如果您在当前模块中覆盖 abar 的输出也会改变。bar() 仍将从 bar.__globals__ 获取 a 的值。 - Ashwini Chaudhary
1
谢谢,我现在对Python中的作用域和导入机制有了更好的理解。 - user65
显示剩余3条评论
1个回答

1

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