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

importlib.import_module无法找到工作目录下新建的模块

问题描述

我想从当前工作目录导入模块,写了这段代码:

import os
import pathlib
import tempfile
from importlib import import_module

with tempfile.TemporaryDirectory() as temp_dir:
    tmp_dir = pathlib.Path(temp_dir)
    (tmp_dir / "foo").mkdir()
    (tmp_dir / "foo" / "__init__.py").write_text("def bar(): pass")
    orig = os.getcwd()
    os.chdir(tmp_dir)
    print(import_module("foo"))
    os.chdir(orig)

但运行时触发了ModuleNotFoundError:

Traceback (most recent call last):
  File "/Users/tdegeus/data/prog/src/conda_envfile/t.py", line 12, in <module>
    print(import_module("foo"))
          ^^^^^^^^^^^^^^^^^^^^
  File "/Users/tdegeus/miniforge3/envs/pre/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'foo'

注:如果目标目录在程序启动前就存在,导入能正常工作。

问题根源

Python启动时会把程序初始运行的当前工作目录加入sys.path(模块搜索路径列表),但后续用os.chdir()切换工作目录后,sys.path并不会自动更新。你的代码里切换到临时目录后,这个临时目录不在sys.path里,所以import机制找不到foo模块。而预先存在的目录如果本来就在sys.path中(比如初始工作目录的子目录),自然能被找到。

解决办法

方法1:手动把临时目录加入sys.path

这是最简单的方案,切换目录后将临时目录路径添加到模块搜索路径:

import os
import sys
import pathlib
import tempfile
from importlib import import_module

with tempfile.TemporaryDirectory() as temp_dir:
    tmp_dir = pathlib.Path(temp_dir)
    (tmp_dir / "foo").mkdir()
    (tmp_dir / "foo" / "__init__.py").write_text("def bar(): pass")
    orig = os.getcwd()
    os.chdir(tmp_dir)
    # 把临时目录加入模块搜索路径
    sys.path.append(str(tmp_dir))
    print(import_module("foo"))
    # 可选:导入完成后移除该路径,避免干扰后续模块搜索
    sys.path.remove(str(tmp_dir))
    os.chdir(orig)

方法2:直接通过文件路径加载模块

不需要切换工作目录,用importlib的工具直接加载指定路径的模块:

import pathlib
import tempfile
from importlib.machinery import SourceFileLoader
from importlib.util import module_from_spec, spec_from_loader

with tempfile.TemporaryDirectory() as temp_dir:
    tmp_dir = pathlib.Path(temp_dir)
    foo_dir = tmp_dir / "foo"
    foo_dir.mkdir()
    init_file = foo_dir / "__init__.py"
    init_file.write_text("def bar(): pass")
    
    # 创建模块加载器和规范
    loader = SourceFileLoader("foo", str(init_file))
    spec = spec_from_loader(loader.name, loader)
    foo_module = module_from_spec(spec)
    loader.exec_module(foo_module)
    
    print(foo_module)
    # 可以直接调用模块里的函数
    foo_module.bar()

方法3:用相对导入方式

保持切换目录的逻辑,通过import_module的package参数实现相对导入:

import os
import pathlib
import tempfile
from importlib import import_module

with tempfile.TemporaryDirectory() as temp_dir:
    tmp_dir = pathlib.Path(temp_dir)
    (tmp_dir / "foo").mkdir()
    (tmp_dir / "foo" / "__init__.py").write_text("def bar(): pass")
    orig = os.getcwd()
    os.chdir(tmp_dir)
    # 用相对导入,package设为空字符串表示当前顶级目录
    print(import_module(".foo", package=""))
    os.chdir(orig)

内容的提问来源于stack exchange,提问作者Tom de Geus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 09:27:28