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

为何不应使用__init__.py区分Python类的公有与私有?

为什么不建议用__init__.py区分Python包的公有与私有类?

我正在实现一个基准测试工具,在其子包benchmark.workload中完成工作负载的设置。为了提升代码易用性,我打算把代码拆分为公有类和私有类,当前项目结构如下:

benchmark/
- __init__.py
- benchmark.py -> Benchmark
- workload/
  - __init__.py
  - loader.py -> WorkloadLoader
  - validation.py -> WorkloadValidation
  - internal_logic1.py -> Internal1
  - internal_logic2.py -> Internal2

我考虑了三种实现方案:

  • 为内部类添加下划线前缀(比如_Internal1),但我觉得下划线前缀更适合蛇形命名法的方法,给驼峰命名的类加下划线会让代码里下划线过多,不太美观。
  • 把所有内部类移到新子包benchmark.workload.internal,但这样会加深文件夹层级,显得繁琐。
  • 只在workload包的__init__.py中导入公有类,这样能简化导入路径:
    # 原导入方式
    from workload.loader import WorkloadLoader
    from workload.validation import WorkloadValidation
    
    # 简化后
    from workload import WorkloadLoader, WorkloadValidation
    
    这种方式看起来能清晰划分模块边界,而且IDE(比如Intellij)能自动处理代码查找的问题,但我看到相关回答对此持反对态度,想知道:为什么我不应使用__init__.py来区分公有与私有类?

示例的__init__.py代码:

# workload/__init__.py:
from .loader import WorkloadLoader
from .validation import WorkloadValidation

反对用__init__.py区分公有/私有类的核心原因

虽然这种方式能简化导入,但反对意见主要集中在维护性、可读性和潜在风险上:

  1. 代码追踪成本提升
    其他开发者看到from workload import WorkloadLoader时,无法直接知道这个类实际定义在loader.py中。如果没有IDE辅助,需要手动查看__init__.py才能找到源码位置,调试和修改代码时会多一层障碍。
  2. 命名冲突隐患
    如果后续在workload的不同子模块中新增了同名类,导入到__init__.py时会直接覆盖之前的导出,这种冲突不会在编译时报错,只有运行时才会暴露,排查难度大。
  3. 偏离__init__.py的设计初衷
    __init__.py的核心作用是标识文件夹为Python包、执行包初始化逻辑(比如设置全局变量、加载配置)。过度用它来做导出管理,会让这个文件承担额外职责,随着项目迭代,__init__.py可能会变得臃肿,难以维护。
  4. 文档与工具兼容性问题
    自动生成文档的工具(比如Sphinx)默认会把__init__.py中导出的类归为workload包的成员,而非实际定义的子模块,导致文档结构与代码物理结构不一致,增加使用者的理解成本。另外,如果后续调整子模块结构(比如合并、拆分文件),需要同步修改__init__.py的导出语句,容易遗漏导致错误。

补充说明

当然,这种导出方式并非完全不可取——很多成熟的Python项目也会在__init__.py中导出核心类来简化用户的导入路径。但反对的声音本质上是在提醒你:这种方式会牺牲一部分代码的直观性,需要权衡易用性和维护成本。如果你的项目团队规模不大、模块结构相对稳定,方案3其实是一个可行的选择。

内容的提问来源于stack exchange,提问作者magum

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:45:29