有人可以在Python中解释__all__吗?

我一直在使用Python越来越多,我一直在看__init__.py文件中设置的variables__all__ 。 有人可以解释这是什么吗?

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

链接到,但这里没有明确提到,正是使用__all__时。 它是一个string列表,用于定义在模块上使用from <module> import *时模块中的哪些符号将被导出。

例如, foo.py的以下代码明确地导出符号barbaz

 __all__ = ['bar', 'baz'] waz = 5 bar = 10 def baz(): return 'baz' 

这些符号可以像这样导入:

 from foo import * print bar print baz # The following will trigger an exception, as "waz" is not exported by the module print waz 

如果上面的__all__被注释掉了,那么这个代码将会执行完成,因为import *的默认行为是从给定的命名空间导入所有不以下划线开头的符号。

参考: https : //docs.python.org/3.5/tutorial/modules.html#importing-from-a-package

注: __all__影响from <module> import *行为。 没有在__all__中提到的成员仍然可以从模块外部访问,并可以from <module> import <member>

我只是补充一点:

所有其他答案都是指模块 。 原来的问题在__init__.py文件中明确提到__all__ ,所以这是关于python 包的

通常, __all__仅在使用import语句的from xxx import *variables时才起作用。 这适用于包和模块。

其他答案解释了模块的行为。 这里详细描述了软件包的确切行为。

简而言之,包级别的__all__模块大致相同,除了处理包中的模块 (与在模块中指定名称相反)。 所以__all__指定了所有的模块,当我们使用from package import *时候,它们应该被加载并导入到当前的命名空间中。

最大的区别是,当你在包的__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

帮助模块module1:

 名称
    模块1

 文件
     module1.py

 数据
     a ='A'
     b ='B'
     c ='C'

$ pydoc module2

帮助模块module2:

 名称
    模块2

 文件
     module2.py

 数据
     __all__ = ['a','b']
     a ='A'
     b ='B'

我在所有的模块中声明了__all__ ,并且强调了内部的细节,在真正的解释器会话中使用以前从未使用过的东西时,这些确实有帮助。

在Python中解释__all__?

我不断看到variables__all__设置在不同的__init__.py文件中。

这是做什么的?

__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将目录视为包含包; 这是为了防止具有通用名称的目录(如string)无意中隐藏稍后在模块searchpath中发生的有效模块。

在最简单的情况下, __init__.py可以只是一个空文件,但也可以执行包的初始化代码或设置__all__variables。

所以__init__.py可以声明一个__all__

pipe理API:

一个包通常由可以相互导入的模块组成,但是必须与__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() 

当创build模块时,他们将不会拥有所有其他的名称。

__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中,你可以在子包级别而不是子包的模块级别进行pipe理。 如果你想添加一个新的名字到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

 import os as _os, sys as _sys 

使用_约定可以更优雅,因为它消除了重新命名名称的冗余。 但是它增加了导入的冗余(如果你有很多),并且很容易忘记一直这么做 – 而且最后你想要的是不得不无限期地支持你只是一个实现细节的东西因为你在命名一个函数的时候忘记了前缀_

我个人在模块开发生命周期的早期写了一个__all__ ,以便其他可能使用我的代码的人知道他们应该使用什么而不使用它。

标准库中的大多数包也使用__all__

避免__all__是有道理的

在以下情况下,坚持使用_前缀约定代替__all__是有意义的:

  • 你仍然处于早期的开发模式,没有用户,并不断调整你的API。
  • 也许你有用户,但是你有unit testing覆盖了API,你仍然在积极地join到API中,并且在开发中进行调整。

一个export装饰器

使用__all__的缺点是必须编写被导出两次的函数和类的名称 – 信息与定义保持分离。 我们可以使用装饰器来解决这个问题。

我从David Beazley的包装谈话中得到了这样一个出口装饰者的想法。 CPython的传统import商似乎performance得很好。 如果你有一个特殊的导入钩子或系统,我不能保证,但是如果你采用它,退出是相当简单的 – 你只需要手动添加名称到__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 * APIconfiguration也会起作用:

 $ 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 

来自(非官方)Python Reference Wiki :

由模块定义的公共名称是通过检查名为__all__的variables的模块名称空间来确定的; 如果被定义,它必须是由该模块定义或导入的名称的string序列。 在__all__中给出的名字都被认为是公开的,并且被要求存在。 如果__all__没有被定义,公共名称集合包括在模块名字空间中find的所有名称,它们不以下划线字符(“_”)开头。 __all__应该包含整个公共API。 它旨在避免意外导出不属于API的项目(例如在模块中导入和使用的库模块)。

__all__ from <module> import *自定义星号

__all__ from <package> import *定制星号


一个模块是一个.py文件, .py导入。

包是一个包含__init__.py文件的目录。 一个包通常包含模块。

 """ cheese.py """ __all__ = ['swiss', 'cheddar'] swiss = 4.99 cheddar = 3.99 gouda = 10.99 

__all__让人们知道模块的“公共”特征。 [ @AaronHall ]另外,pydoc认可他们。 [ @Longpoke ]

模块导入*

看看swisscheddar是如何进入本地命名空间的,但不是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__ ,任何符号(不以下划线开头)都可用。


没有*import不受__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文件中__all__是一个具有公共模块或其他对象名称的string列表。 这些function可用于通配符导入。 与模块一样, __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... ] 

通配符导入…应该避免,因为他们[迷惑]读者和许多自动化工具。

[ PEP 8 ,@ToolmakerSteve]

__all__用于loggingPython模块的公共API。 虽然是可选的,但应该使用__all__

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

由模块定义的公共名称是通过检查名为__all__的variables的模块名称空间来确定的; 如果被定义,它必须是由该模块定义或导入的名称的string序列。 在__all__中给出的名字都被认为是公开的,并且被要求存在。 如果__all__没有被定义,公共名称集合包括在模块名称空间中find的所有名称,它们不以下划线字符('_')开始。 __all__应该包含整个公共API。 它旨在避免意外导出不属于API的项目(例如在模块中导入和使用的库模块)。

PEP 8使用类似的措辞,但是也清楚地表明,当__all__不存在时,导入的名称不属于公共API的一部分:

为了更好地支持自省,模块应该使用__all__属性在其公共API中显式声明名称。 将__all__设置为空列表表示该模块没有公共API。

[…]

应始终将导入的名称视为实现细节。 其他模块不得间接访问此类导入的名称,除非它们是包含模块的API的明确logging部分,例如os.path或从子模块公开function的包的__init__模块。

而且,正如其他答案中所指出的那样, __all__用于为包打开通配符导入 :

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