我在__init__.py文件中看到__all__。它做什么?
当前回答
它是该模块的公共对象列表,由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__从<模块>导入中自定义**和来自<package>import*。
模块是要导入的.py文件。
包是包含__init__.py文件的目录。包通常包含模块。
模块
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__让人类了解模块的“公共”特性。[@AaronHall]而且,pydoc认出了他们。[@Longpoke]
从模块导入*
看看swiss和cheddar是如何被引入本地命名空间的,而不是gouda:
>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined
如果没有__all__,任何符号(不以下划线开头)都将可用。
不带*的进口不受__all影响__
导入模块
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)
从模块导入名称
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)
将模块导入为localname
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)
包装
在包__all__的__init__.py文件中,有一个字符串列表,其中包含公共模块或其他对象的名称。这些功能可用于通配符导入。与模块一样,__all__在从包中导入通配符时自定义*。[@MartinStettner]
以下是Python MySQL连接器__init__.py的摘录:
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
包的默认情况是星号,不带__all__,这很复杂,因为明显的行为代价很高:使用文件系统搜索包中的所有模块。相反,在我阅读文档时,只导入__init__.py中定义的对象:
如果未定义__all__,sound.effects import*中的语句不会将sound.eeffects包中的所有子模块导入当前命名空间;它只确保包sound.effects已经导入(可能在__init__.py中运行任何初始化代码),然后导入包中定义的任何名称。这包括__init__.py定义的任何名称(以及显式加载的子模块)。它还包括以前的import语句显式加载包的任何子模块。
最后,随处可见的堆积如山的答案、教授和漫画家,这是一个受人尊敬的传统,这是对一开始就提出问题的指责:
通配符导入。。。应该避免,因为它们会混淆读者和许多自动化工具。
[PEP 8,@ToolmakerSteve]
PEP8中定义如下:
全局变量名称(我们希望这些变量只在一个模块中使用。)这些约定与函数的约定大致相同。为通过from M import*使用而设计的模块应该使用__all__机制来防止导出全局变量,或者使用旧的惯例,在这些全局变量前加下划线(您可能希望这样做,以表明这些全局变量是“模块非公共的”)。
PEP8为Python代码提供了编码约定,该Python代码包含Python主发行版中的标准库。你越是遵循这一点,你就越接近最初的意图。
简短的回答
__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文档。
我只是准确地补充一下:
所有其他答案均涉及模块。最初的问题明确提到__init__.py文件中的__all__,所以这是关于python包的。
通常,__all__仅在使用import语句的from xxx import*变体时生效。这适用于软件包和模块。
其他答案中解释了模块的行为。这里详细描述了包的确切行为。
简而言之,包级别的__all__与模块的作用大致相同,只是它处理包中的模块(与在模块中指定名称相反)。因此__all__指定了当我们使用from package import*时应加载并导入到当前命名空间中的所有模块。
最大的区别是,当您在包的__init__.py中省略__all__的声明时,包import*中的语句根本不会导入任何内容(除了文档中解释的例外,请参见上面的链接)。
另一方面,如果在模块中省略__all__,则“星号导入”将导入模块中定义的所有名称(不以下划线开头)。
推荐文章
- Numpy Max vs amax vs maximum
- 我应该在.gitignore文件中添加Django迁移文件吗?
- 每n行有熊猫
- 实例属性attribute_name定义在__init__之外
- 如何获取在Python中捕获的异常的名称?
- 第一次出现的值大于现有值的Numpy
- 如何从Python函数中返回两个值?
- 前一个月的Python日期
- Python中方括号括起来的列表和圆括号括起来的列表有什么区别?
- Python日志记录不输出任何东西
- 每n秒运行特定代码
- SQLAlchemy是否有与Django的get_or_create等价的函数?
- 如何将python datetime转换为字符串,具有可读格式的日期?
- 美丽的汤和提取div及其内容的ID
- 在Python中重置生成器对象