从不同的python模块获取所有子类



在项目中,我想创建这样一个结构:

main_module
   ├── __init__.py
   ├── base
   │   ├── __init__.py
   │   └── base.py
   └── custom_base
       ├── __init__.py
       └── custom.py

其中base.py包含基本处理程序类

from abc import ABC, abstractmethod

class BaseHandler(ABC):
@abstractmethod
def __call__(self, something):
pass

每次都需要创建新的处理程序添加到结构

└── custom_base
├── __init__.py
└── custom.py

所有处理程序都将在主结构外部的单独.py文件中同时使用。

handlers = get_handlers()
for handler in handlers:
handler("some message")

这就是我面临的问题。我想通过一个函数获得BaseHandler的所有子类,但如果python以前没有看到过这些子类,我就无法获得它们。有没有";"干净";这个问题的解决方案?

我为此创建了一个实用程序脚本。我不能声称它是";"干净";方法,但效果很好。请参阅以下代码。

import glob
import importlib
import inspect
import pathlib
from main_module.base.base import BaseHandler

def get_handlers(source_package="main_module.custom_base"):
"""
Tries to discover the handlers in the given package recursively.
Package name from root is expected.
"""
search_dir = (pathlib.Path(source_package.replace(".", "/"))).absolute().as_posix()
module_files = glob.glob(search_dir + "/**/*.py", recursive=True)
module_files = [x for x in module_files if "__init__" not in x]
module_files = [pathlib.Path(x).as_posix() for x in module_files]
module_files = [source_package + "." + x.replace(search_dir + "/", "").replace(".py", "").replace("/", ".") for
x in module_files]
__modules = [inspect.getmembers(importlib.import_module(x)) for x in module_files]
handlers = []
for member_modules in __modules:
for _name, member in member_modules:
if inspect.isclass(member) and issubclass(member, BaseHandler) and member != BaseHandler:
handlers.append(member)
return handlers

if __name__ == '__main__':
handlers = get_handlers()
for handler in handlers:
print(handler)

这个脚本基本上扫描指定包中的文件,识别模块,选择BaseHandler的子类并返回。好吧,这可以用一种理想的方式即兴创作。这种方法的一些缺点

  • 如果子类有一些部分导入,这可能是个问题
  • 这将基于工作目录工作,因此它不是库的选择[库中的处理程序将不会被发现]

这是一种更加自动化的发现方法。但对于一个万无一失的解决方案,您可以考虑使用.env文件,并将那里的FQNMs配置为os变量,然后使用它来加载您的子类。

如果它在某种程度上帮助了你,我很高兴:-(

最新更新