我有以下源代码树:
planets/
earth.py
mars.py
util.py
main.py
使用以下代码:
planets / earth.py:
def moon() -> None:
print('moon')
planets / mars.py:
def phobos() -> None:
print('phobos')
util.py:
import planets.mars # yes, just this
main.py:
import planets.earth
import util
def foobar() -> None:
planets.mars.phobos()
if __name__ == '__main__':
foobar()
请注意,在“ main.py”中,我没有明确导入“ planets.mars”。当我运行“ main.py”时,没有得到我期望的错误,而是得到了输出:
phobos
在我看来,因为我在“ util.py”中导入“ planets.mars”,然后在“ main.py”中导入“ util.py”,所以“ main.py”可以看到“ planets.mars”因此,我可以从“ main.py”中调用“ planets.mars.phobos()”。
但是,当我从“ main.py”中删除“ import planets.earth”时,当我尝试运行“ main.py”时,出现“ NameError:未定义名称'planets'”异常。这似乎表明“ planets.mars”通过导入“ util.py”而被过渡导入“ main.py”并不是真正的事情,实际上是我的Python解释器中有一个错误。 / p>
有人能为我揭开这个谜吗?我在Debian 9上使用的是CPython版本3.7.0。
谢谢!
答案 0 :(得分:3)
导入planets.earth
将planets
模块添加到main.py
的命名空间中,并将planets
和planets.earth
插入sys.modules
中。
在planets.mars
中导入util.py
会将planets.mars
插入sys.modules
中,并使名称mars
可用作planets
的属性。
在main.py中访问planets.mars.phobos
时,可以通过planet.mars
的命名空间中的名称planets
访问main.py
。
如果从planets.earth
中删除了main.py
的导入,则planets
不再在模块名称空间中,因此引发了NameError
。
如果删除了util.py
的导入,则不会将mars
设置为planets
的属性,因此会引发AttributeError
。
这种行为可能会造成混淆,这也是为什么许多软件包都具有__init__.py
来导入子模块/子软件包的原因之一,因此在导入软件包时它们都可用。