如何实现通用导入自动加载插件模块并遍历插件类
如何实现通用导入自动加载插件模块并遍历插件类
嘿,我太懂你这种每天手动加导入的烦躁了——虽然import *确实算不上最佳实践,但在这种插件频繁新增的场景里,自动加载绝对能帮你省超多重复工作。我给你一步步拆解怎么实现:
首先,你得在src/plugins文件夹(就是放a.py、b.py这些插件的目录)里,新建或者修改__init__.py文件,Python靠这个文件识别包,我们要把自动加载的逻辑写在这里:
import os import importlib # 定义from src.plugins import *时要导入的类名列表 __all__ = [] # 用来统一存所有插件类,方便后续批量实例化和遍历 plugin_classes = [] # 获取当前插件文件夹的路径 plugin_dir = os.path.dirname(__file__) # 遍历文件夹下的所有文件 for filename in os.listdir(plugin_dir): # 只处理.py文件,排除__init__.py本身 if filename.endswith('.py') and filename != '__init__.py': # 去掉.py后缀,得到模块名(比如a.py → a) module_name = filename[:-3] try: # 从当前包导入这个模块 module = importlib.import_module(f'.{module_name}', package=__name__) # 对应你插件里的类名规则:文件名首字母大写(比如a.py里的A类) class_name = module_name.capitalize() # 从模块中取出对应的类 plugin_class = getattr(module, class_name) # 把类名加入__all__,这样from ... import *就能导入这些类 __all__.append(class_name) # 把类加入统一列表,方便后续批量处理 plugin_classes.append(plugin_class) except AttributeError: # 容错处理:如果模块里找不到对应类,打印警告后跳过 print(f"⚠️ 警告:模块{module_name}中未找到{class_name}类,已跳过该模块") except Exception as e: # 捕获其他异常,避免一个插件出错导致所有加载失败 print(f"❌ 加载模块{module_name}时出错:{str(e)}")
接下来在你的main.py里就轻松多了:
- 用
from src.plugins import *就能直接拿到所有插件类(比如A、B、N这些),同时还能导入我们定义好的plugin_classes列表。 - 要遍历插件的话,先批量实例化所有插件(记得传入你的config配置),然后直接循环就行:
# 这里替换成你实际的配置对象 config = {"some_config_key": "config_value"} # 批量实例化所有插件 plugins = [plugin_cls(config) for plugin_cls in plugin_classes] # 遍历插件,打印每个插件的plugin属性 for plugin in plugins: print(plugin.plugin)
以后你新增插件文件(比如c.py,里面写好C类),完全不用手动加导入语句,__init__.py会自动帮你加载,plugin_classes列表里也会自动包含新的C类,直接就能用。
最后补两个小提醒:
- 这个逻辑依赖你每个插件文件的类名是文件名首字母大写(比如a.py对应A类),如果你的命名规则不一样,只要调整
class_name的生成逻辑就行,比如文件名是驼峰的话,就改成对应的驼峰类名。 - 虽然
import *确实有争议,但在这种插件自动加载的场景下,只要你通过plugin_classes统一管理插件类,代码的可读性和维护性其实不会受太大影响,省下来的时间可是实打实的。
备注:内容来源于stack exchange,提问作者Swannie




