如何自动动态导入当前目录模块,实现驱动扩展无需修改抽象类?
动态导入目录下所有驱动类的解决方案
项目结构
/ my_project |- GeneralDriverAbstract.py |- A_Driver.py # 继承抽象类 |- A_DriverAlpha.py |- A_DriverBeta.py |- B_Driver.py # 继承抽象类 |- B_DriverAlpha.py |- B_DriverBeta.py |- Suffix.py |- other_files.py
需求说明
需要在GeneralDriverAbstract.py中动态导入同目录下所有类,新增驱动时仅需添加对应文件和Suffix.py中的枚举值,无需修改抽象类。用户传入驱动名(如A_Driver)和后缀(如alpha)后,可自动创建A_DriverAlpha这类匹配的对象并完成配置。
现有问题
- 第一种方法:编写
__init__.py定义__all__后,执行from . import *仍报NameError,无法直接引用类 - 第二种方法:将导入逻辑移到抽象类中,出现递归导入问题,且同样无法找到类名
方案一:修正__init__.py实现全局导入
原__init__.py仅定义了__all__但未实际导入模块内的类,修改后可自动导入所有类并暴露到命名空间:
import os import importlib current_dir = os.path.dirname(__file__) # 遍历目录下所有非__init__的py文件 for filename in os.listdir(current_dir): if filename.endswith('.py') and not filename.startswith('__init__'): module_name = filename[:-3] # 动态导入当前包下的模块 module = importlib.import_module(f'.{module_name}', package=__name__) # 将模块中的类添加到当前__init__的命名空间 for attr_name in dir(module): attr = getattr(module, attr_name) if isinstance(attr, type): # 仅导入类对象 globals()[attr_name] = attr # 定义__all__,支持from . import *导入所有类 __all__ = [name for name, obj in globals().items() if isinstance(obj, type)]
在GeneralDriverAbstract.py中使用:
from . import * # 直接实例化类 test = A_Driver()
方案二:在抽象类中安全动态导入(避免递归)
若需在抽象类内部实现导入逻辑,需避免循环导入,并将类存入类属性统一管理:
import os import importlib import inspect class GeneralDriverAbstract: # 存储所有导入的驱动类,键为类名,值为类对象 _driver_classes = {} def __init__(self, driver_name, suffix): # 拼接目标类名(如A_Driver + Alpha → A_DriverAlpha) target_class_name = f"{driver_name}{suffix.capitalize()}" target_class = self._driver_classes.get(target_class_name) if not target_class: raise ValueError(f"找不到驱动类: {target_class_name}") # 实例化目标驱动并保存 self.driver_instance = target_class() # 此处可添加自定义配置逻辑 # 动态导入同目录下所有模块(排除自身和__init__) current_file = os.path.basename(__file__) current_dir = os.path.dirname(__file__) for filename in os.listdir(current_dir): if filename.endswith('.py') and filename != current_file and not filename.startswith('__init__'): module_name = filename[:-3] # 导入当前包下的模块 module = importlib.import_module(f'.{module_name}', package=__name__) # 将模块中的类存入_driver_classes for name, obj in inspect.getmembers(module, inspect.isclass): GeneralDriverAbstract._driver_classes[name] = obj
使用示例:
from GeneralDriverAbstract import GeneralDriverAbstract from Suffix import Suffix # 假设Suffix是枚举类,如Suffix.ALPHA.value为"alpha" # 创建驱动实例 driver = GeneralDriverAbstract("A_Driver", Suffix.ALPHA.value) # 通过driver.driver_instance操作具体驱动
问题原因解析
- 第一种方法失败:仅定义
__all__不会自动导入模块内的类,需手动将类注入__init__.py的命名空间 - 第二种方法失败:未使用相对路径导入(缺少
.前缀)导致导入全局模块,且未将类存入可访问的命名空间;递归导入是因为驱动类可能反向导入抽象类,通过将导入逻辑放在类定义后、排除自身文件可解决
内容的提问来源于stack exchange,提问作者Dark Patate
相关产品推荐
相关产品推荐

