You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 01:12:45