Python中__all__的含义及使用

Python中__all__的含义及使用

技术背景

在Python编程中,我们经常会使用import语句来导入模块或包中的内容。当使用from <module> import *这种通配符导入方式时,Python需要知道应该导入哪些内容。__all__就是用来控制这种通配符导入行为的一个特殊变量。它可以在模块文件(包括__init__.py文件)中使用,帮助我们明确指定哪些内容是模块或包的公共接口,哪些内容是内部实现细节。

实现步骤

1. 在模块中使用__all__

在一个普通的Python模块(.py文件)中,__all__是一个列表,其中包含了字符串形式的变量、函数或类的名称。当使用from <module> import *时,只有__all__中指定的内容会被导入。

1
2
3
4
5
6
7
# foo.py
__all__ = ['bar', 'baz']

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

在另一个文件中使用通配符导入:

1
2
3
4
5
6
from foo import *

print(bar) # 输出: 10
print(baz()) # 输出: baz
# 下面的代码会触发异常,因为 "waz" 没有被导出
# print(waz)
PYTHON

2. 在包中使用__all__

在Python中,一个包含__init__.py文件的目录被视为一个包。__init__.py文件可以用来初始化包,并且可以设置__all__变量。当使用from <package> import *时,__all__中指定的模块或对象会被导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# package/__init__.py
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar']

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

# package/module_2.py
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar:
pass
PYTHON

在另一个文件中导入包:

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

核心代码

模块中__all__的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
# module.py
__all__ = ['public_function', 'PublicClass']

def public_function():
return "This is a public function."

class PublicClass:
def __init__(self):
self.message = "This is a public class."

def _private_function():
return "This is a private function."

PYTHON
1
2
3
4
5
6
7
8
9
10
# main.py
from module import *

# 可以正常调用
print(public_function())
obj = PublicClass()
print(obj.message)

# 下面的代码会触发NameError,因为 _private_function 未被导出
# print(_private_function())
PYTHON

包中__all__的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# package/__init__.py
from .submodule1 import *
from .submodule2 import *
__all__ = ['submodule1_function', 'Submodule2Class']

# package/submodule1.py
__all__ = ['submodule1_function']

def submodule1_function():
return "This is a function from submodule1."

# package/submodule2.py
__all__ = ['Submodule2Class']

class Submodule2Class:
def __init__(self):
self.message = "This is a class from submodule2."

PYTHON
1
2
3
4
5
6
# main.py
from package import *

print(submodule1_function())
obj = Submodule2Class()
print(obj.message)
PYTHON

最佳实践

明确公共接口

在开发模块或包时,尽早定义__all__,让其他开发者清楚知道哪些内容是可以使用的公共接口,哪些是内部实现细节。

避免使用通配符导入

虽然__all__可以控制通配符导入的行为,但通配符导入会使命名空间变得混乱,建议尽量使用明确的导入方式,如from <module> import <name>

使用导出装饰器

为了避免在__all__中重复书写函数和类的名称,可以使用导出装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

# main.py
from lib import export
__all__ = []

@export
def foo():
pass

@export
def bar():
'bar'

def main():
print('main')

if __name__ == '__main__':
main()

PYTHON

常见问题

1. 不定义__all__时的行为

如果在模块中不定义__all__,使用from <module> import *会导入所有不以下划线开头的名称。如果在包的__init__.py中不定义__all__from <package> import *只会导入__init__.py中定义的名称,而不会自动导入包中的子模块。

2. __all__是否影响其他导入方式

__all__只影响from <module> import *from <package> import *这种通配符导入方式。其他导入方式,如import <module>from <module> import <name>不受__all__的影响。

3. __all__必须是列表吗

根据Python文档,__all__必须是一个由字符串组成的序列,所以也可以使用元组,例如__all__ = ('some_name',)


Python中__all__的含义及使用
https://119291.xyz/posts/python-all-meaning-and-usage/
作者
ww
发布于
2025年4月18日
许可协议