我在__init__.py文件中看到__all__。它做什么?


当前回答

它是该模块的公共对象列表,由import*解释。它覆盖了隐藏以下划线开头的所有内容的默认设置。

其他回答

它是该模块的公共对象列表,由import*解释。它覆盖了隐藏以下划线开头的所有内容的默认设置。

__all__用于记录Python模块的公共API。虽然它是可选的,但应使用__all__。

以下是Python语言参考的相关摘录:

模块定义的公共名称是通过检查模块名称空间中名为__all__的变量来确定的;如果定义了,它必须是一系列字符串,这些字符串是该模块定义或导入的名称。__all__中给出的名称都被视为公共名称,必须存在。如果未定义__all__,则公共名称集包含模块名称空间中不以下划线字符('_')开头的所有名称__all__应该包含整个公共API。它旨在避免意外导出不属于API的项目(例如在模块中导入和使用的库模块)。

PEP 8使用了类似的措辞,但它也明确指出,当__all__不存在时,导入的名称不是公共API的一部分:

为了更好地支持内省,模块应该使用__all__属性在其公共API中显式声明名称。将__all__设置为空列表表示模块没有公共API。[...]导入的名称应始终视为实现细节。其他模块不得依赖对此类导入名称的间接访问,除非它们是包含模块API的显式文档部分,例如os.path或包的__init__模块,该模块公开子模块的功能。

此外,正如其他答案中指出的,__all__用于为包启用通配符导入:

import语句使用以下约定:如果包的__init__.py代码定义了一个名为__all__的列表,那么当遇到from package import*时,它将被视为应该导入的模块名称列表。

简短的回答

__all__影响<module>import*语句。

答案很长

考虑以下示例:

foo
├── bar.py
└── __init__.py

在foo/__init__.py中:

(隐式)如果我们不定义__all__,那么from foo import*将只导入foo/__init__.py中定义的名称。(显式)如果我们定义__all__=[],那么from foo import*将不导入任何内容。(显式)如果我们定义__all__=[<name1>,…],那么from foo import*将只导入这些名称。

注意,在隐式情况下,python不会导入以_开头的名称。但是,您可以使用__all__强制导入此类名称。

您可以在此处查看Python文档。

PEP8中定义如下:

全局变量名称(我们希望这些变量只在一个模块中使用。)这些约定与函数的约定大致相同。为通过from M import*使用而设计的模块应该使用__all__机制来防止导出全局变量,或者使用旧的惯例,在这些全局变量前加下划线(您可能希望这样做,以表明这些全局变量是“模块非公共的”)。

PEP8为Python代码提供了编码约定,该Python代码包含Python主发行版中的标准库。你越是遵循这一点,你就越接近最初的意图。

__all__影响from foo import*的工作方式。

模块主体(但不在函数或类主体中)内的代码可以在from语句中使用星号(*):

from foo import *

*请求将foo模块的所有属性(以下划线开头的属性除外)绑定为导入模块中的全局变量。当foo有一个__all__属性时,该属性的值是由该类型的from语句绑定的名称列表。

如果foo是一个包,并且它的__init__.py定义了一个名为__all__的列表,那么当遇到from foo import*时,它将被视为应该导入的子模块名称列表。如果__all__未定义,foo import*的语句将导入包中定义的任何名称。这包括__init__.py定义的任何名称(以及显式加载的子模块)。

注意__all__不一定是列表。根据import语句的文档,如果已定义,__all__必须是由模块定义或导入的字符串序列。因此,您不妨使用元组来节省一些内存和CPU周期。如果模块定义了一个公共名称,请不要忘记逗号:

__all__ = ('some_name',)

另请参见为什么“import*”不好?