Python模块开发是否需要添加__all__列表控制import *导入行为?
Python 子模块扁平化导出的规则与
__all__适用场景说明 场景复现
当前项目结构:
A0 ├─ B0 │ ├─ __init__.py │ └─ b0.py ├─ B1 │ ├─ __init__.py │ └─ b1.py └─ __init__.py
叶子模块b0.py的代码:
# __all__ = ['func_b0'] def func_b0():... def _func_b0():... def __func_b0():...
在A0/B0/__init__.py写入from .b0 import *后,即可直接通过from A0.B0 import func_b0导入目标函数,无需携带叶子模块名b0。
规则说明
默认import *的导出逻辑
Python 原生对from module import *的行为有明确默认规则:
若模块未定义
__all__列表,import *只会导出所有不以下划线开头的模块级名称,单下划线_、双下划线__开头的名称都会被排除在导出范围外。
按这个规则,你当前b0.py里的三个函数:
func_b0无下划线前缀,会被默认导出_func_b0、__func_b0以下划线开头,默认不会被import *导出
这种靠命名规则控制导出的方式完全符合语法规范,对于简单的工具模块场景,维护成本确实更低——只需要给不对外暴露的内部函数、类加单下划线前缀即可,不需要额外维护导出列表。
__all__的设计目的
__all__不是为了替代下划线命名规则,而是用来覆盖默认导出逻辑,解决默认规则处理不了的需求:
- 需要对外暴露以下划线开头的公共接口(比如版本兼容用的别名函数)
- 需要导出非当前模块定义的名称(比如在
__init__.py中聚合多个子模块的接口时,明确列出对外暴露的完整API,避免把导入的依赖、内部子模块本身意外暴露出去) - 需要严格锁定公共API边界:如果没有
__all__,后续在叶子模块里新增的不带下划线的内部辅助函数,会被自动导出到上层包;定义__all__后,只有列表内的名称会被导出,不会出现API意外泄露的问题 - 对接工具链:IDE自动补全、文档生成工具通常会优先读取
__all__作为模块的公开API清单。
实践建议
- 如果你写的是小型内部工具模块,所有公共API都不会以下划线开头,也不需要严格锁定导出边界,完全可以只用单下划线前缀标记内部成员,靠默认规则控制
import *行为,不用额外写__all__。 - 如果你的模块需要对外发布、或者公共API比较复杂需要明确边界,建议显式定义
__all__。 - 额外提醒:模块级的内部成员用单下划线前缀标记即可,双下划线开头的名称会触发Python的名称修饰(name mangling),是为类的私有成员设计的,不适合用在模块层级。
规范依据
相关规则在PEP 8中有明确约定:
- 模块中非公共的实现细节,使用单下划线前缀标记
- 当需要明确公开API列表时,应该显式定义
__all__,列表内的顺序即为公开API的推荐导出顺序。
内容的提问来源于stack exchange,提问作者Little Train
相关产品推荐
相关产品推荐

