import语句(link)的Python文档包含以下内容:
由模块定义的公共名称是通过检查模块名称空间中名为
__all__
的变量来确定的;如果已定义,则它必须是由该模块定义或导入的名称的字符串序列。
模块(link)的Python文档包含看似矛盾的声明:
如果程序包的
__init__.py
代码定义了名为__all__
的列表,则将其视为遇到from package import *
时应导入的模块名称的列表。
然后给出一个示例,其中__init__.py
文件不导入任何内容,仅将__all__
定义为该程序包中某些模块的名称。
我已经测试了使用__all__
的两种方法,并且似乎都可行;实际上,一个人可以在同一__all__
值内进行混合和匹配。
例如,考虑目录结构
foopkg/
__init__.py
foo.py
__init__.py
包含的位置
# Note no imports
def bar():
print("BAR")
__all__ = ["bar", "foo"]
NOTE:我知道不应该在__init__.py
文件中定义函数。我只是为了说明相同的__all__
可以导出当前名称空间中确实存在的名称和不存在的名称。
以下代码运行,似乎自动导入了foo模块:
>>> from foopkg import *
>>> dir()
[..., 'bar', 'foo']
为什么__all__
属性具有这种奇怪的双重行为?
文档似乎对于应该如何使用还不清楚,只在我链接的每个地方都提到了它的两个方面之一。我知道总体目的是显式设置通配符导入所导入的名称,但被其他看似自动导入的行为所迷惑。这只是一个魔术快捷方式,它也避免了必须写出导入文件吗?
您可以将foopkg(文件夹)想象为一个foopkg.py模块
在您的示例中,您可以这样做吗?:
from foopkg import foo
因此__all__
中的__init__.py
的行为类似于__all__
中的foopkg.py
。该功能是将您from foopkg import *
时可以导入的内容列入白名单。(希望这个比喻不会引起混淆)