Python中__all__的含义和作用

Python中__all__的含义和作用

技术背景

在Python编程中,当我们使用from <module> import *语句导入模块时,有时需要精确控制哪些符号(变量、函数、类等)会被导入。__all__就是Python提供的一种机制,用于声明模块或包的“公共”接口,它可以让开发者明确指定在使用from <module> import *时要导入的符号。

实现步骤

模块中使用__all__

在模块中,__all__是一个字符串列表,定义了使用from <module> import *时要导出的符号。例如,在foo.py文件中:

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

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

此时,使用from foo import *只能导入barbaz,而waz不会被导入。如果没有定义__all__from <module> import *会导入所有不以_开头的符号。

包中使用__all__

在包的__init__.py文件中,__all__同样可以用来控制from <package> import *的行为。例如,有如下包结构:

1
2
3
4
package
├── __init__.py
├── module_1.py
└── module_2.py

__init__.py中可以这样定义__all__

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

这样,当使用from package import *时,只会导入fooBar

核心代码

模块中__all__的使用示例

1
2
3
4
5
6
# foo.py
__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())
# 以下代码会触发异常,因为"waz"未被导出
# print(waz)

包中__all__的使用示例

1
2
3
4
# package/__init__.py
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar']
1
2
3
4
# package/module_1.py
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
1
2
3
4
# package/module_2.py
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
1
2
3
4
# 使用包
import package
package.foo()
package.Bar()

使用装饰器简化__all__的定义

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# main.py
from lib import export
__all__ = []

@export
def foo(): pass

@export
def bar():
'bar'

def main():
print('main')

if __name__ == '__main__':
main()

最佳实践

  • 在开发模块或包时,尽早定义__all__,让其他开发者清楚知道哪些是公共接口,哪些是实现细节。
  • 如果模块或包的API经常变动,且还没有用户,可以暂时使用_前缀来标记私有符号,而不使用__all__
  • 当使用__all__时,可以考虑使用装饰器来避免重复书写导出的符号名。

常见问题

1. __all__对其他导入方式有影响吗?

__all__只影响from <module> import *from <package> import *的导入行为,对于其他导入方式,如import <module>from <module> import <name>等没有影响。

2. 如果不定义__all__会怎样?

  • 在模块中,from <module> import *会导入所有不以_开头的符号。
  • 在包中,from <package> import *只会导入__init__.py中定义的符号(除非有其他显式加载的子模块)。

3. __all__必须是列表吗?

不一定,__all__可以是任何字符串序列,如元组。使用元组可以节省一些内存和CPU周期,但如果只定义一个公共名称,不要忘记加逗号,如__all__ = ('some_name',)


Python中__all__的含义和作用
https://119291.xyz/posts/python-all-variable-explanation/
作者
ww
发布于
2025年5月26日
许可协议