如何自动将Python子包模块中的类导入__init__.py?
自动导入子包模块中的类(无需修改__init__.py)
当然有办法实现,核心思路是在子包的__init__.py里写一段代码,自动遍历并导入所有模块中的类,不用每次加新模块都手动改这个文件。
通用实现方案(适配多类/任意类名)
在子包的__init__.py中加入以下代码:
import importlib import pkgutil # 获取当前子包的完整名称 __pkg_name__ = __name__ __all__ = [] # 遍历子包下的所有模块(跳过子包) for _, module_full_name, is_subpkg in pkgutil.walk_packages(__path__, __pkg_name__ + '.'): if not is_subpkg: # 导入模块 module = importlib.import_module(module_full_name) # 筛选模块自身定义的类(排除从其他地方导入的类) for attr_name in dir(module): attr = getattr(module, attr_name) if isinstance(attr, type) and attr.__module__ == module_full_name: # 将类挂载到子包的命名空间 globals()[attr_name] = attr __all__.append(attr_name)
这段代码会自动完成:
- 遍历子包下所有非子包的模块
- 导入每个模块
- 找出模块里自己定义的所有类(排除外部导入的类)
- 把这些类放到子包的命名空间里,同时更新
__all__列表,支持from 子包 import *
精准适配(单模块单类+命名规则)
如果你的每个模块只对应一个类,且类名和模块名遵循固定规则(比如模块名是user.py,类名是User),可以用更精准的写法,避免导入多余内容:
import importlib import pkgutil import warnings __pkg_name__ = __name__ __all__ = [] for _, module_full_name, is_subpkg in pkgutil.walk_packages(__path__, __pkg_name__ + '.'): if not is_subpkg: module = importlib.import_module(module_full_name) # 从模块全名中提取短名称(比如`my_subpkg.user` -> `user`) module_short_name = module_full_name.split('.')[-1] # 转成大驼峰作为预期类名 expected_class_name = module_short_name.capitalize() try: target_class = getattr(module, expected_class_name) globals()[expected_class_name] = target_class __all__.append(expected_class_name) except AttributeError: # 模块不符合规则时抛出警告,不中断程序 warnings.warn(f"模块 {module_full_name} 未找到预期类 {expected_class_name},已跳过")
注意事项
- 要避免循环导入:确保子包内的模块之间没有互相导入导致的依赖问题
- 如果模块中有其他不需要导出的类,可以调整筛选条件(比如给需要导出的类加装饰器,然后判断装饰器标记)
__all__列表可选,如果你不需要支持import *可以删掉相关代码
内容的提问来源于stack exchange,提问作者Minura Punchihewa
相关产品推荐
相关产品推荐

