关于语法:有人能解释一下Python中的 __all__吗?

Can someone explain __all__ in Python?

我越来越多地使用python,并且不断看到在不同的__init__.py文件中设置的变量__all__。有人能解释一下这是怎么回事吗?


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

例如,foo.py中的以下代码显式导出符号barbaz

1
2
3
4
5
__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

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

1
2
3
4
5
6
7
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 import *的行为。__all__中没有提到的成员仍然可以从模块外部访问,可以通过from import 导入。


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


我只是想说清楚:

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

一般情况下,__all__只在使用import语句的from xxx import *变体时起作用。这适用于软件包和模块。

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

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

最大的区别是,当您在包的__init__.py中省略了__all__的声明时,声明from package import *将不会导入任何内容(除了文档中解释的例外情况,请参见上面的链接)。

另一方面,如果在模块中省略__all__,则"星型导入"将导入模块中定义的所有名称(不以下划线开头)。


Explain __all__ in Python?

Ok.

I keep seeing the variable __all__ set in different __init__.py files.

Ok.

What does this do?

Ok.

__all__是做什么的?

它从模块中声明语义上"公共"的名称。如果__all__中有一个名字,用户应该使用它,他们可以期望它不会改变。好的。

它还将产生程序性影响:好的。import *

模块中的__all__,例如module.py:好的。

1
__all__ = ['foo', 'Bar']

意味着从模块中导入import *时,仅导入__all__中的那些名称:好的。

1
from module import *               # imports foo and Bar

文档工具

文档和代码自动完成工具(实际上,应该)也可以检查__all__以确定模块中可用的显示名称。好的。__init__.py使目录成为python包

来自文档:好的。

The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as string, from unintentionally hiding valid modules that occur later on the module search path.

Ok.

In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable.

Ok.

因此,__init__.py可以为一个包声明__all__。好的。管理API:

包通常由可以互相导入的模块组成,但这些模块必须与__init__.py文件绑定在一起。这个文件使目录成为实际的python包。例如,假设您有以下内容:好的。

1
2
3
4
 package/
   |-__init__.py # makes directory a Python package
   |-module_1.py
   |-module_2.py

__init__.py中,您写道:好的。

1
2
from module_1 import *
from module_2 import *

module_1中,你有:好的。

1
__all__ = ['foo',]

module_2中,你有:好的。

1
__all__ = ['Bar',]

现在,您已经提供了一个完整的API,其他人在导入您的包时可以使用它,比如:好的。

1
2
3
import package
package.foo()
package.Bar()

它们不会有您在创建模块时使用的所有其他名称,而这些模块会把package名称空间搞得一团糟。好的。__init__.py中的__all__

在做了更多的工作之后,也许你已经决定模块太大了,需要拆分。因此,您可以执行以下操作:好的。

1
2
3
4
5
6
7
8
 package/
   |-__init__.py
   |-module_1/
   |  |-__init__.py
   |  |-foo_implementation.py
   |-module_2/
      |-__init__.py
      |-Bar_implementation.py

在每个__init__.py中,您声明一个__all__,例如在模块1中:好的。

1
2
from foo_implementation import *
__all__ = ['foo']

和模块的__init__.py:好的。

1
2
from Bar_implementation import *
__all__ = ['Bar']

而且,您可以很容易地向API添加您可以在子包级别而不是子包的模块级别管理的内容。如果要向API添加一个新名称,只需更新__init__.py,例如在模块_2中:好的。

1
2
3
from Bar_implementation import *
from Baz_implementation import *
__all__ = ['Bar', 'Baz']

如果您还没有准备好在顶级API中发布Baz,在顶级__init__.py中,您可以:好的。

1
2
3
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的可用性,他们可以使用它:好的。

1
2
import package
package.Baz()

但如果他们不知道,其他工具(如pydoc)就不会通知他们。好的。

以后,当Baz准备好黄金时段时,您可以更改:好的。

1
2
3
from module_1 import *
from module_2 import *
__all__ = ['foo', 'Bar', 'Baz']

预混___all__的比较:

默认情况下,python将导出不以_开头的所有名称。你当然可以依靠这种机制。实际上,python标准库中的一些包确实依赖于此,但要做到这一点,它们将其导入命名为别名,例如,在ctypes/__init__.py中:好的。

1
import os as _os, sys as _sys

使用_约定可能更优雅,因为它消除了重新命名名称的冗余。但是它增加了导入的冗余(如果您有很多导入),并且很容易忘记始终如一地这样做——您最不想做的就是无限期地支持一些您打算只作为实现细节的东西,仅仅是因为在命名函数时忘记给EDOCX1加前缀(26)。好的。

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

标准库中的大多数包也使用__all__。好的。避开__all__是有意义的

在下列情况下,坚持使用_前缀约定代替__all__:好的。

  • 您仍然处于早期开发模式,没有用户,并且不断地调整您的API。
  • 也许你确实有用户,但是你有涵盖API的UnitTests,而且你仍然在积极地添加到API中并在开发中进行调整。

装饰设计师

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

我从大卫比兹利关于包装的演讲中得到了这样一个出口装潢师的想法。这种实现在CPython的传统进口商中似乎很有效。如果您有一个特殊的导入钩子或系统,我不保证,但是如果您采用它,退出是非常简单的-您只需要手动将名称重新添加到__all__中。好的。

例如,在实用程序库中,您将定义decorator:好的。

1
2
3
4
5
6
7
8
9
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__的地方,您可以这样做:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ 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()

无论是作为主函数运行还是由另一个函数导入,这都可以很好地工作。好的。

1
2
3
4
5
6
$ cat > run.py
import main
main.main()

$ python run.py
main

使用import *提供API也可以工作:好的。

1
2
3
4
5
6
7
8
9
10
11
$ 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

好啊。


它还更改了pydoc将显示的内容:

模1.Py

1
2
3
a ="A"
b ="B"
c ="C"

模块2.Py

1
2
3
4
5
__all__ = ['a', 'b']

a ="A"
b ="B"
c ="C"

$ PyDOC模块1

1
2
3
4
5
6
7
8
9
10
11
12
Help on module module1:

NAME
    module1

FILE
    module1.py

DATA
    a = 'A'
    b = 'B'
    c = 'C'

$ PyDOC模块2

1
2
3
4
5
6
7
8
9
10
11
12
Help on module module2:

NAME
    module2

FILE
    module2.py

DATA
    __all__ = ['a', 'b']
    a = 'A'
    b = 'B'

我在我的所有模块中声明__all__,并强调了内部细节,当在现场口译员会话中使用以前从未使用过的东西时,这些都非常有用。


来自(非官方)python参考wiki:

The public names defined by a module are determined by checking the module's namespace for a variable named __all__; if defined, it must be a sequence of strings which are names defined or imported by that module. The names given in __all__ are all considered public and are required to exist. If __all__ is not defined, the set of public names includes all names found in the module's namespace which do not begin with an underscore character ("_"). __all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module).


__all__自定义from import *中的星号__all__自定义from import *中的星号

模块是要导入的.py文件。

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

模块

1
2
3
4
5
6
7
""" cheese.py - an example module"""

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__让人类了解模块的"公共"功能。[@aaronhall]同样,pydoc也认识它们。[@longpoke]

从模块导入*

请参见如何将swisscheddar引入本地命名空间,而不是将gouda引入本地命名空间:

1
2
3
4
5
6
7
>>> 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__的影响。导入模块

1
2
3
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

从模块导入名称

1
2
3
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

将模块作为localname导入

1
2
3
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

包装

在包的__init__.py文件中,__all__是带有公共模块或其他对象名称的字符串列表。这些功能可用于通配符导入。与模块一样,当从包中导入通配符时,__all__自定义*。[@martinstettner]

下面是python mysql connector __init__.py的摘录:

1
2
3
4
5
6
7
8
9
10
11
12
13
__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

    # Some useful constants
    'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
    'HAVE_CEXT',

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

默认情况下,包的星号没有__all__,这很复杂,因为明显的行为会很昂贵:使用文件系统搜索包中的所有模块。相反,在我阅读文档时,只导入__init__.py中定义的对象:

If __all__ is not defined, the statement from sound.effects import * does not import all submodules from the package sound.effects into the current namespace; it only ensures that the package sound.effects has been imported (possibly running any initialization code in __init__.py) and then imports whatever names are defined in the package. This includes any names defined (and submodules explicitly loaded) by __init__.py. It also includes any submodules of the package that were explicitly loaded by previous import statements.

Wildcard imports ... should be avoided as they [confuse] readers and many automated tools.

[PEP 8,@toolmakersteve]


简短回答

__all__影响from import *报表。

长回答

考虑这个例子:

1
2
3
foo
├── bar.py
└── __init__.py

foo/__init__.py中:

  • (隐式)如果我们不定义__all__,那么from foo import *将只导入foo/__init__.py中定义的名称。

  • (明确)如果我们定义__all__ = [],那么from foo import *将不导入任何内容。

  • (明确)如果我们定义__all__ = [ , ... ],那么from foo import *将只导入这些名称。

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

您可以在这里查看python文档。


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

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

The public names defined by a module are determined by checking the module’s namespace for a variable named __all__; if defined, it must be a sequence of strings which are names defined or imported by that module. The names given in __all__ are all considered public and are required to exist. If __all__ is not defined, the set of public names includes all names found in the module’s namespace which do not begin with an underscore character ('_'). __all__ should contain the entire public API. It is intended to avoid accidentally exporting items that are not part of the API (such as library modules which were imported and used within the module).

PEP 8使用了类似的措辞,尽管它也清楚地表明,当缺少__all__时,导入的名称不是公共API的一部分:

To better support introspection, modules should explicitly declare the names in their public API using the __all__ attribute. Setting __all__ to an empty list indicates that the module has no public API.

[...]

Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module's API, such as os.path or a package's __init__ module that exposes functionality from submodules.

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

The import statement uses the following convention: if a package’s __init__.py code defines a list named __all__, it is taken to be the list of module names that should be imported when from package import * is encountered.


除了现有的答案,__all__不必是一个列表。根据import语句的文档,如果定义了,__all__必须是由模块定义或导入的字符串序列。所以您也可以使用一个元组来保存一些内存和CPU周期。不要忘记逗号,以防模块定义单个公用名:

__all__ = ('some_name',)