带有子模块导入的命名空间

namespace with submodule imports

我想使用简单的列表理解来为我的包中的模块设置 __all__。我注意到,当我从我自己的模块之一导入某些内容时,模块名称被添加到命名空间,而不仅仅是我正在导入的内容。这与导入内置或第三方包时不同。

- foo
  - __init__.py
  - bar.py
  - baz.py

__init__.py

import os as _os

from numpy.random import randint as _randint

import foo.bar as _bar

from foo.baz import foobar

__all__ = [x for x in globals() if not x.startswith('_')]

我预计:

>>> import foo
>>> foo.__all__
['foobar']

但我得到:

>>> import foo
>>> foo.__all__
['bar', 'baz', 'foobar']

我知道我可以扩展我对 __all__ 的列表理解以过滤掉 ModuleType 但我想知道为什么我自己的模块的行为不同。我真的很想能够像处理其他包一样使用前导下划线来处理这个问题。我也尝试过使用 dir()locals()vars() 而不是 globals(),但结果是一样的。

更新
出于好奇,我还将 foobar 导入 bar.py 并打印 globals() 并且 'bar' 不包括在内。所以,我的模块似乎只添加到 __init__.py 个文件中的命名空间?

在评论中感谢@MisterMiyagi。

我只会引用官方文档来证实这一点 5.4.2. Submodules:

When a submodule is loaded using any mechanism [...] a binding is placed in the parent module’s namespace to the submodule object.

例如,在您的情况下,如果包 foo 有一个子模块 bar,在导入 foo.bar 之后,foo 将有一个属性 bar绑定到子模块 foo.bar.