You need to enable JavaScript to run this app. Spyder下Python导入模块触发ImportDenier无find_spec属性报错
优惠活动
大模型
产品
解决方案
定价
更多

Spyder下Python导入模块触发ImportDenier无find_spec属性报错

模块导入异常问题说明

项目基础结构

my_module
   |-> _sub_module
   |     |-> test_fun.py
   |-> test_fun1.py
   |-> run.py
   |-> __init__.py

各文件基础内容:

  • test_fun.py:
def test_fun():
    pass
  • test_fun1.py:
def test_fun1():
    pass
  • 初始状态run.py内容:
from my_module.test_fun1 import test_fun1
from my_module._sub_module.test_fun import test_fun
  • 根目录__init__.py为空文件

基础报错现象

当前复现环境为Anaconda安装的Spyder,配套Python 3.8.5版本。
正常运行场景:从my_module的父目录执行run.py,全量导入的情况下脚本可正常执行。
触发报错的条件:注释掉run.py中第一行导入语句,仅保留from my_module._sub_module.test_fun import test_fun,使用Spyder的runfile功能执行时触发异常,完整堆栈如下:

runfile('C:/Users/###/Documents/GitLab/test_project/my_module/run.py')
Reloaded modules: my_module, my_module.test_fun1, my_module._sub_module.test_fun
Traceback (most recent call last):
  File "<frozen importlib._bootstrap>", line 908, in _find_spec
AttributeError: 'ImportDenier' object has no attribute 'find_spec'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\###\Documents\GitLab\test_project\my_module\run.py", line 4, in <module>
    from my_module._sub_module.test_fun import test_fun
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 910, in _find_spec
  File "<frozen importlib._bootstrap>", line 884, in _find_spec_legacy
  File "C:\Users\###\Anaconda3\lib\site-packages\IPython\external\qt_loaders.py", line 48, in find_module
    if path:
  File "<frozen importlib._bootstrap_external>", line 1183, in __len__
  File "<frozen importlib._bootstrap_external>", line 1162, in _recalculate
  File "<frozen importlib._bootstrap_external>", line 1158, in _get_parent_path
KeyError: 'my_module'

核心待解答问题:

  • 该报错的具体触发逻辑是什么
  • 为什么导入内容完全无关、仅共享命名空间前缀的第一行导入语句,可完全规避报错

结构调整后的复现验证

将run.py移到my_module的上级目录(即test_project路径下)后,复现逻辑发生变化:第一次执行仅保留第二行导入的run.py时脚本可正常运行,但连续第二次执行相同脚本时,就会复现相同的ImportDenier报错,对应堆栈如下:

runfile('C:/Users/###/Documents/GitLab/test_project/run.py', wdir='C:/Users/###/Documents/GitLab/test_project')

runfile('C:/Users/###/Documents/GitLab/test_project/run.py', wdir='C:/Users/###/Documents/GitLab/test_project')
Reloaded modules: my_module, my_module._sub_module.test_fun
Traceback (most recent call last):
  File "<frozen importlib._bootstrap>", line 908, in _find_spec
AttributeError: 'ImportDenier' object has no attribute 'find_spec'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\###\Documents\GitLab\test_project\run.py", line 4, in <module>
    from my_module._sub_module.test_fun import test_fun
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 910, in _find_spec
  File "<frozen importlib._bootstrap>", line 884, in _find_spec_legacy
  File "C:\Users\###\Anaconda3\lib\site-packages\IPython\external\qt_loaders.py", line 48, in find_module
    if path:
  File "<frozen importlib._bootstrap_external>", line 1183, in __len__
  File "<frozen importlib._bootstrap_external>", line 1162, in _recalculate
  File "<frozen importlib._bootstrap_external>", line 1158, in _get_parent_path
KeyError: 'my_module'

交叉验证结果:

  • 直接在系统普通命令行、独立IPython控制台运行该脚本时,无法复现上述报错
  • 问题根源与Spyder的内置执行逻辑直接相关

报错根因拆解

  • 堆栈中的核心异常触发源来自IPython内置的qt_loaders.py模块:其中定义的ImportDenier导入钩子原本用于拦截Qt相关模块的重复导入,仅实现了Python 3.3之前旧版导入协议要求的find_module方法,没有实现新版导入协议要求的find_spec方法。
  • Spyder的runfile执行逻辑默认开启用户模块自动重载机制:每次执行脚本前,会将上下文已加载的自定义模块做卸载处理,把对应模块从sys.modules字典中移除,但不会同步更新路径解析器内存储的父模块路径缓存。
  • 当脚本直接导入下划线开头的私有子模块(即_sub_module)时,导入流程不会提前完成父包my_module的初始化:导入器在遍历所有注册的导入钩子做路径校验时,会优先尝试调用ImportDenier的find_spec方法,因方法缺失触发异常,流程自动 fallback 到旧版的find_module分支,此时尝试读取已经被从sys.modules中移除的my_module的路径属性做长度判断,就会触发路径解析的KeyError。
  • 第一行导入能规避报错的逻辑:from my_module.test_fun1 import test_fun1会在流程最开始完成my_module根包的全量加载,将根包的路径信息同步写入sys.modules缓存,即使后续模块重载流程做了缓存清理,根包的路径解析链路已经提前建立,不会触发ImportDenier钩子的旧版逻辑校验分支。

临时规避方案

  • 调整导入顺序,先导入根包下任意非下划线开头的公开子模块,再导入私有子模块
  • 在Spyder的工具>偏好设置>Python解释器中,关闭用户模块自动重载选项,避免每次执行前清空导入缓存
  • 升级IPython和Spyder到最新版本,新版本已为ImportDenier补充find_spec方法的实现,从根源上避免旧版导入协议的逻辑冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 11:06:04