有人可以用 Python 解释__all__吗?

我越来越多地使用 Python,并且不断看到在不同的__init__.py文件中设置了变量__all__ 。有人可以解释这是什么吗?

答案

__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)

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

__all__ = ['foo', 'Bar']
from module import *               # imports foo and Bar
package
├── __init__.py
├── module_1.py
└── module_2.py
from pathlib import Path

package = Path('package')
package.mkdir()

(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")

package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")

package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")
import package
package.foo()
package.Bar()
package
├── __init__.py
├── module_1
│   ├── foo_implementation.py
│   └── __init__.py
└── module_2
    ├── Bar_implementation.py
    └── __init__.py
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
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
import package
package.Baz()
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
import os as _os, sys as _sys
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
$ 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
$ 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

我只是添加这是为了精确:

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

通常, __all__仅在使用import语句的from xxx import *变体时才起作用。这适用于软件包以及模块。

模块的行为在其他答案中进行了说明。包的确切行为在此处详细描述。

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

最大的不同是,当您省略软件包__init__.py__all__声明时from package import *的语句将根本不会导入任何内容(文档中有例外说明,请参见上面的链接)。

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

a = "A"
b = "B"
c = "C"
__all__ = ['a', 'b']

a = "A"
b = "B"
c = "C"
Help on module module1:

NAME
    module1

FILE
    module1.py

DATA
    a = 'A'
    b = 'B'
    c = 'C'
Help on module module2:

NAME
    module2

FILE
    module2.py

DATA
    __all__ = ['a', 'b']
    a = 'A'
    b = 'B'
""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99
>>> 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
>>> 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)
__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

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

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

摘自(非官方)Python 参考 Wiki

通过检查模块的命名空间中名为__all__的变量,可以确定模块定义的公共名称。如果已定义,则必须是由该模块定义或导入的名称的字符串序列。 __all__中给出的名称均被视为公开名称,并且必须存在。如果未定义__all__ ,则公共名称集将包含在模块命名空间中找到的所有名称,这些名称不以下划线字符(“_”)开头。 __all__应该包含整个公共 API。目的是避免意外导出不属于 API 的项目(例如,在模块内导入和使用的库模块)。

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

__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 *时应导入的模块名称的列表。

from foo import *
__all__ = ('some_name',)