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

Python中__init__.py使用别名导入子模块后原模块名仍暴露在包命名空间的疑问

Python中__init__.py使用别名导入子模块后原模块名仍暴露在包命名空间的疑问

这确实是个容易让人困惑的点,我刚接触Python包导入机制的时候也踩过类似的坑——这不是Python的bug,而是包导入时的特殊设计导致的,咱们一步步拆解来理解:

为什么会出现这种情况?

当你在包的__init__.py里执行from . import submodule as sm时,Python的包加载逻辑是这样的:

  1. 首先找到并加载submodule子模块,自动将其注册到包的命名空间(也就是package.__dict__),所以submodule这个名字会出现在包的dir()结果里;
  2. 然后再将这个已加载的子模块的引用,赋值给你指定的别名sm。

这和普通脚本里的from package import submodule as sm逻辑完全不同:后者是从包的命名空间里取出已存在的submodule引用,赋值给当前脚本的sm,但不会在脚本命名空间里创建submodule这个名字——两者的场景一个是“在包内部加载子模块”,一个是“从外部导入已存在的模块引用”,逻辑自然有区别。

怎么实现你想要的效果?

如果你希望test.py无法访问package.submodule,可以用以下两种方法:

方法1:导入后主动删除原模块名

在__init__.py里导入别名后,手动删除submodule这个名字的引用:

from . import submodule as sm
del submodule  # 移除包命名空间里的原模块名
print(dir())

此时运行test.py,尝试访问package.submodule会抛出AttributeError: module 'package' has no attribute 'submodule',完全符合你的预期。

方法2:用importlib手动加载子模块

使用importlib.import_module加载子模块,这种方式不会自动将原模块名注册到包的命名空间:

import importlib
sm = importlib.import_module(".submodule", __name__)
print(dir())

运行后dir()里只会有sm,test.py同样无法访问package.submodule。

验证效果

用方法1修改后,__init__.py的dir()输出会变成:

['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'sm']

test.py运行时会直接报错,完美实现“隐藏原模块名”的需求。

备注:内容来源于stack exchange,提问作者Amess

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:49:38