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

如何从文件夹动态加载所有模块?加载时遇ModuleNotFoundError报错

解决动态加载插件模块时的ModuleNotFoundError问题

我看到你在尝试动态加载plugins目录下的模块时遇到了ModuleNotFoundError,问题出在__init__.py里无法导入first模块。这是因为手动用importlib加载模块时,Python的模块搜索路径默认不包含你的plugins目录,而且动态加载的模块没有被正确识别为包的一部分。下面给你几种可行的解决方案:

方法1:将plugins目录添加到Python的模块搜索路径

最简单的方式是把plugins的绝对路径加入sys.path,这样Python就能找到该目录下的所有模块了。修改你的loader.py:

import importlib.util
import os
import sys  # 新增导入sys模块

search_dir = "./plugins"
plugins_module = []

def loader():
    path = os.path.realpath(search_dir)
    # 将plugins目录添加到sys.path
    if path not in sys.path:
        sys.path.append(path)
    
    for module in os.listdir(path):
        # 跳过__pycache__等非py文件
        if not module.endswith(".py") or module == "__pycache__":
            continue
        spec = importlib.util.spec_from_file_location(module.split(".")[0], os.path.join(path,module))
        plugin_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(plugin_module)
        plugins_module.append(plugin_module)

loader()

这样修改后,__init__.py里的from first import hello就能正常找到first模块了。

方法2:在__init__.py中使用相对导入

另一种方式是利用Python的相对导入语法,让__init__.py从当前包内导入first模块。修改plugins/__init__.py:

from .first import hello  # 加上点号表示相对当前包导入

def main():
    print("hello from __init__.py")
    hello()

不过这种方式需要确保动态加载时,plugins目录被识别为一个包。你可以在加载__init__.py时,给模块设置__package__属性,修改loader.py里的加载逻辑:

import importlib.util
import os

search_dir = "./plugins"
plugins_module = []

def loader():
    path = os.path.realpath(search_dir)
    for module in os.listdir(path):
        if not module.endswith(".py") or module == "__pycache__":
            continue
        module_name = module.split(".")[0]
        spec = importlib.util.spec_from_file_location(module_name, os.path.join(path,module))
        plugin_module = importlib.util.module_from_spec(spec)
        # 如果是__init__.py,设置__package__属性为plugins
        if module == "__init__.py":
            plugin_module.__package__ = "plugins"
        spec.loader.exec_module(plugin_module)
        plugins_module.append(plugin_module)

loader()

这种方式更符合Python的包结构规范,不会污染全局的sys.path。

方法3:使用importlib.import_module(更简洁的动态加载方式)

如果你不需要手动处理spec的细节,可以用importlib.import_module来加载模块,前提是先把plugins目录的父目录添加到sys.path,并把plugins作为包来导入:

修改loader.py:

import importlib
import os
import sys

search_dir = "./plugins"
plugins_module = []

def loader():
    # 获取plugins目录的父目录路径
    parent_dir = os.path.dirname(os.path.realpath(search_dir))
    if parent_dir not in sys.path:
        sys.path.append(parent_dir)
    
    # 先导入plugins包
    plugins_package = importlib.import_module("plugins")
    plugins_module.append(plugins_package)
    
    # 加载plugins下的其他模块(比如first.py)
    for module in os.listdir(search_dir):
        if module.endswith(".py") and module != "__init__.py" and module != "__pycache__":
            module_name = f"plugins.{module.split('.')[0]}"
            plugin_module = importlib.import_module(module_name)
            plugins_module.append(plugin_module)

loader()

这种方式更贴近Python原生的导入逻辑,代码也更简洁,同时能自然处理包内的相对导入。

你可以根据自己的需求选择其中一种方法,个人推荐方法2或3,它们更符合Python的模块包设计理念。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:57:37