python 动态加载所有子类

2020/09/05 技术

python 动态加载所有子类

python 类提供 __subclass__ 方法, 可用于获取所有子类列表. 同时, 提供 issubclass, 判断一个类是否是另一个类的子类.

1. __subclass__ 使用示例

使用方法见示例:


import unittest


class TestSubClass(unittest.TestCase):
    def setUp(self) -> None:
        pass

    def testSubClass(self):
        """ """

        class A(object):
            pass

        class B(A):
            pass

        class C(A):
            pass

        for sub_class in A.__subclasses__():
            print(sub_class)
            self.assertTrue(issubclass(sub_class, A))

        # <class 'x.TestSubClass.testSubClass.<locals>.B'>
        # <class 'x.TestSubClass.testSubClass.<locals>.C'>

    def testSubClassV2(self):
        """ """

        class A(object):
            pass

        class B(A):
            pass

        class C(B):
            pass

        self.assertEqual(len(A.__subclasses__()), 1)
        self.assertEqual(len(B.__subclasses__()), 1)

        self.assertTrue(issubclass(B, A))
        self.assertTrue(issubclass(C, B))
        self.assertTrue(issubclass(C, A))

2. 使用 __subclass__importlib 动态加载基类的所有实现类

示例:


import glob
import importlib.util
import os
import shutil
import sys
import unittest
from collections import OrderedDict


class TestDynamicImport(unittest.TestCase):
    def setUp(self) -> None:
        self.script_dir: str = os.path.abspath("./script")

        self.prepare_scripts()

    def prepare_scripts(self):
        """ """

        def _create_script(_class_name: str, _script_file: str):
            content = """
from collections import OrderedDict

class {class_name}(OrderedDict):
    pass
            """.format(class_name=_class_name)
            with open(_script_file, "w") as f:
                f.write(content)

        if os.path.exists(self.script_dir):
            shutil.rmtree(self.script_dir)

        os.makedirs(self.script_dir, exist_ok=True)

        # create SB
        _create_script(_class_name="SB", _script_file=os.path.join(self.script_dir, "sb.py"))

        # create SC
        _create_script(_class_name="SC", _script_file=os.path.join(self.script_dir, "sc.py"))

    def testDynamicImport(self):
        """ """
        # 加载所有脚本
        py_file_list = [py_file for py_file in glob.glob("{}/*.py".format(os.path.abspath(self.script_dir).rstrip("/")))]
        print("{} script found!".format(len(py_file_list)))

        for py_file in py_file_list:
            script_module_name = "scripts.{}".format(os.path.basename(py_file)[:-len(".py")])
            spec = importlib.util.spec_from_file_location(script_module_name, py_file)
            script_module = importlib.util.module_from_spec(spec)
            sys.modules[script_module_name] = script_module
            spec.loader.exec_module(script_module)

        # 获取所有脚本类
        for sub_class in OrderedDict.__subclasses__():
            print(sub_class)
            self.assertTrue(issubclass(sub_class, OrderedDict))

        # <class 'scripts.sb.SB'>
        # <class 'scripts.sc.SC'>           

Search

    Table of Contents