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

如何让Python中的import与from import行为产生差异?

Python导入系统特性导致两种导入形式差异的原因及实现方式

问题重现

from foo import BAR          # 执行成功
log.info(f"{dir(BAR)=}")     # 执行成功
import foo.BAR               # 执行成功
log.info(f"{dir(foo.BAR)=}") # 执行失败,抛出AttributeError:模块foo中无BAR属性

环境说明:Python 3.11,foo为目录,foo/__init__.py为空文件,foo/BAR.py存在且包含函数、类等顶层元素。

核心原因:模块命名空间与子模块的绑定分离

Python导入系统的核心特性之一是:子模块不会自动成为父模块的属性,除非父模块显式导入并绑定它。

  • from foo import BAR:会先加载foo模块,再加载foo.BAR模块,最后将foo.BAR这个模块对象直接导入到当前代码的命名空间里,但不会在foo模块自身的命名空间中添加BAR属性。
  • import foo.BAR:同样会加载foo和foo.BAR模块,但也不会主动修改foo的命名空间。当你尝试访问foo.BAR时,Python会去foo模块的__dict__中查找BAR这个键,而空的__init__.py没有做任何绑定操作,自然会抛出AttributeError。

刻意实现该效果的方法

要维持这种“能导入子模块但无法通过父模块访问”的状态,只需做到两点:

  • 保持foo/__init__.py为空,绝对不要在其中添加from . import BAR或import BAR这类代码——这类代码会把BAR模块绑定到foo的命名空间中,让foo.BAR可访问。
  • 不在任何其他代码中修改foo模块的命名空间,比如不要执行import foo, sys; foo.BAR = sys.modules['foo.BAR']这类手动绑定的操作。

补充:即使foo.BAR无法通过父模块访问,你依然可以通过sys.modules['foo.BAR']直接获取到已加载的BAR模块对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:01:00