Python中模块全限定名与对象名冲突时的解析顺序疑问
Python导入时命名冲突的解析顺序规则
结合你的场景,核心问题在于:你在foo/__init__.py里定义了logger对象,但有时from foo import logger会导入foo.logger子模块而非这个对象,根源是Python导入时的优先级规则和模块缓存机制。
核心解析顺序规则
- 子模块优先于模块内同名对象(存在缓存或对应文件结构时)
执行from foo import logger时,Python的查找逻辑是:- 先检查
sys.modules(Python的模块缓存字典)里是否存在foo.logger模块。如果之前已经导入过这个子模块,直接返回缓存里的模块对象。 - 若缓存中没有,会检查文件系统是否存在
foo/logger目录(或foo/logger.py文件)。如果存在,Python会先尝试导入这个子模块,将其加入sys.modules后返回。 - 只有当以上两种情况都不满足时,Python才会去
foo模块(即__init__.py)的命名空间里查找名为logger的对象、变量或其他成员。
- 先检查
对应你的场景分析
正常运行的情况:
执行from foo import logger前,sys.modules里没有foo.logger,且没有其他代码触发过该子模块的导入。此时Python会直接读取foo/__init__.py,导入里面定义的logger对象,调用info方法自然正常。报错的情况:
之前的代码中已经有地方导入过foo.logger子模块(比如执行过import foo.logger或者from foo.logger import xxx),此时sys.modules里已经缓存了foo.logger模块。当你再执行from foo import logger时,Python直接返回缓存里的子模块,而这个模块本身没有info方法,就会抛出AttributeError。
额外说明
如果想确保导入的是__init__.py里的logger对象,可以在导入时明确重命名:
from foo import logger as foo_logger
另外,__init__.py里的__all__主要影响from foo import *的导出范围,对单个导入的优先级没有改变。
内容的提问来源于stack exchange,提问作者strisunshine
相关产品推荐
相关产品推荐

