Python解释器中的错误,还是我误解了软件包导入机制?

时间:2019-04-22 16:58:51

标签: python python-3.x python-import python-3.7

我有以下源代码树:

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。

谢谢!

1 个答案:

答案 0 :(得分:3)

导入planets.earthplanets模块添加到main.py的命名空间中,并将planetsplanets.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来导入子模块/子软件包的原因之一,因此在导入软件包时它们都可用。