我愈来愈多地使用Python,而且不断看到在不一样的__init__.py
文件中设置了变量__all__
。 有人能够解释这是什么吗? html
我只是添加这是为了精确: python
全部其余答案均涉及模块 。 最初的问题在__init__.py
文件中明确提到__all__
,因此这是关于python 包的 。 mysql
一般, __all__
仅在使用import
语句的from xxx import *
变体时才起做用。 这适用于软件包以及模块。 sql
模块的行为在其余答案中进行了说明。 包的确切行为在此处详细描述。 api
简而言之,包级别的__all__
与模块具备几乎相同的功能,除了它处理包中的模块 (与在模块中指定名称相反)。 所以__all__
指定当咱们from package import *
使用时应加载并导入到当前名称空间的全部模块。 app
最大的区别是,当您省略软件包的__init__.py
的__all__
声明时from package import *
的语句将根本不会导入任何内容(文档中有例外说明,请参见上面的连接)。 函数
另外一方面,若是在模块中省略__all__
,则“已加星标的导入”将导入模块中定义的全部名称(不如下划线开头)。 工具
它还更改了pydoc将显示的内容: 单元测试
module1.py 测试
a = "A" b = "B" c = "C"
module2.py
__all__ = ['a', 'b'] a = "A" b = "B" c = "C"
$ pydoc module1
Help on module module1: NAME module1 FILE module1.py DATA a = 'A' b = 'B' c = 'C'
$ pydoc module2
Help on module module2: NAME module2 FILE module2.py DATA __all__ = ['a', 'b'] a = 'A' b = 'B'
我在全部模块中都声明了__all__
,并强调了内部细节,当使用在实时解释器会话中从未使用过的功能时,这些确实有用。
用Python解释__all__吗?
我一直看到在不一样的
__init__.py
文件中设置了变量__all__
。这是作什么的?
__all__
作什么的? 它从模块中声明语义上的“公共”名称。 若是__all__
有一个名称,则但愿用户使用它,而且他们能够指望它不会更改。
它也会对程序产生影响:
import *
__all__
在模块中,例如module.py
:
__all__ = ['foo', 'Bar']
表示从模块import *
时,仅导入__all__
中的那些名称:
from module import * # imports foo and Bar
文档和代码自动完成工具也可能(实际上应该)检查__all__
以肯定哪些名称能够从模块中显示出来。
__init__.py
使目录成为Python包 从文档 :
__init__.py
文件是使Python将目录视为包含包所必需的; 这样作是为了防止具备通用名称(例如字符串)的目录无心间隐藏了稍后在模块搜索路径中出现的有效模块。在最简单的状况下,
__init__.py
能够只是一个空文件,但它也能够为程序包执行初始化代码或设置__all__
变量。
所以__init__.py
能够声明包的__all__
。
一个包一般由能够互相导入但又必须与__init__.py
文件捆绑在一块儿的模块组成。 该文件使目录成为实际的Python包。 例如,假设您具备如下条件:
package/ |-__init__.py # makes directory a Python package |-module_1.py |-module_2.py
在__init__.py
编写:
from module_1 import * from module_2 import *
在module_1
您具备:
__all__ = ['foo',]
在module_2
您有:
__all__ = ['Bar',]
如今,您已经提供了一个完整的api,供其余人在导入您的软件包时使用,以下所示:
import package package.foo() package.Bar()
并且,它们将不会具备您在建立使整个package
名称空间混乱的模块时使用的全部其余名称。
__init__.py
__all__
通过更多的工做,也许您已经肯定模块太大,须要拆分。 所以,您须要执行如下操做:
package/ |-__init__.py |-module_1/ | |-__init__.py | |-foo_implementation.py |-module_2/ |-__init__.py |-Bar_implementation.py
而后在每一个__init__.py
声明一个__all__
,例如在module_1中:
from foo_implementation import * __all__ = ['foo']
和module_2的__init__.py
:
from Bar_implementation import * __all__ = ['Bar']
并且,您能够轻松地将内容添加到您能够在子包级别而不是子包的模块级别管理的API中。 若是要向API添加新名称,只需更新__init__.py
,例如在module_2中:
from Bar_implementation import * from Baz_implementation import * __all__ = ['Bar', 'Baz']
若是您还不许备在顶级API中发布Baz
,则能够在顶级__init__.py
进行如下操做:
from module_1 import * # also constrained by __all__'s from module_2 import * # in the __init__.py's __all__ = ['foo', 'Bar'] # further constraining the names advertised
若是您的用户知道Baz
的可用性,则可使用它:
import package package.Baz()
可是若是他们不知道,其余工具(例如pydoc )将不会通知他们。
当Baz
准备好迎接黄金时段时,您能够稍后更改它:
from module_1 import * from module_2 import * __all__ = ['foo', 'Bar', 'Baz']
_
和__all__
: 默认状况下,Python将导出全部不以_
开头的名称。 您固然能够依靠这种机制。 实际上,Python标准库中的某些软件包确实依赖于此,可是要这样作,它们会为本身的导入ctypes/__init__.py
别名,例如在ctypes/__init__.py
:
import os as _os, sys as _sys
使用_
约定可能更优雅,由于它消除了再次命名名称的麻烦。 但这增长了导入的冗余(若是有不少导入的话),很容易忘记一向地执行此操做-最后要作的就是无限期地支持您打算仅做为实现细节的内容,只是由于您在命名函数时忘记了_
前缀。
我在开发生命周期的早期就亲自为模块编写了__all__
,以便其余可能使用个人代码的人知道应该使用而不该该使用什么。
标准库中的大多数软件包还使用__all__
。
__all__
才有意义 在如下状况下,使用_
前缀约定代替__all__
是有意义的:
export
装潢商 使用__all__
的缺点是必须编写两次导出的函数和类的名称-而且信息与定义保持分开。 咱们能够使用装饰器解决此问题。
我从大卫·比兹利(David Beazley)关于包装的演讲中想到了这样的出口装饰商。 在CPython的传统导入器中,此实现彷佛运行良好。 若是您有一个特殊的导入挂钩或系统,我不能保证,可是若是您采用它,撤消它就很简单了-您只须要手动将名称从新添加到__all__
所以,例如在实用程序库中,您将定义装饰器:
import sys def export(fn): mod = sys.modules[fn.__module__] if hasattr(mod, '__all__'): mod.__all__.append(fn.__name__) else: mod.__all__ = [fn.__name__] return fn
而后,在定义__all__
执行此操做:
$ cat > main.py from lib import export __all__ = [] # optional - we create a list if __all__ is not there. @export def foo(): pass @export def bar(): 'bar' def main(): print('main') if __name__ == '__main__': main()
不管是做为主程序运行仍是由其余函数导入,此方法均可以正常工做。
$ cat > run.py import main main.main() $ python run.py main
带有import *
API配置也将起做用:
$ cat > run.py from main import * foo() bar() main() # expected to error here, not exported $ python run.py Traceback (most recent call last): File "run.py", line 4, in <module> main() # expected to error here, not exported NameError: name 'main' is not defined
__all__
自定义*
from <module> import *
__all__
自定义*
from <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)
>>> import cheese as ch >>> ch.swiss, ch.cheddar, ch.gouda (4.99, 3.99, 10.99)
在包的__init__.py
文件中, __init__.py
__all__
是包含公用模块或其余对象名称的字符串列表。 这些功能可用于通配符导入。 与模块同样, __all__
在从软件包中通配符导入时自定义*
。 [ @MartinStettner ]
这是Python MySQL Connector __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__
,则from sound.effects import *
的语句不会将包sound.effects
全部子模块导入当前名称空间; 它仅确保已导入包sound.effects
(可能在__init__.py
运行任何初始化代码),而后导入包中定义的任何名称。 这包括__init__.py
定义的任何名称(以及明确加载的子模块)。 它还包括之前的import语句显式加载的包的全部子模块。
应避免使用通配符导入,由于它们会使读者和许多自动化工具感到困惑。
[ PEP 8 ,@ ToolmakerSteve]
__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 *
时应导入的模块名称的列表。