• Python无需import自动加载指定包路径中所有python文件及其中的类和方法


    Python无需import自动加载指定包路径中所有python文件及其中的类和方法

    我需要更新我的公众号,使它具备查询课表、查询电费及查询未完成作业的功能。这些功能使用爬虫实现,如果写在一两个文件里就太杂了,为进行解耦和便于扩展功能,准备更新下项目架构。具体是将每个功能写成一个类,然后通过分配器来决定实现哪个功能。当接收用户的数据后,经过分配器调用所有的功能,然后由每个功能的解析器解析用户文本,如果符合本功能就继续执行,直到返回结果,如果不符合则返回空,让分配器继续执行下一个功能。问题来了,我不想一个个将每个功能类导入到执行器脚本中,于是想试试是否能自动自动读取相关包中的对应功能类,形成一个列表。于是产生此文

    第一步,准备文件
    项目目录

    ​ 因为还是测试,所以比较简陋,准备一个text.py作为分配器使用,新建一个名为functions的包,其中每个python文件中存在一个类,为一个功能,这些类继承自一个父类BaseFunction

    image-20221102150005348

    functions.BaseFunction.py
    class BaseFunction:
        def run(self):
            return None
    
    • 1
    • 2
    • 3
    functions.CurriculumFunction.py
    from functions.BaseFunction import BaseFunction
    
    
    class Curriculum(BaseFunction):
    
        def run(self):
            return "查询到课表"
    
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    functions.HomeworkFunction.py
    from functions.BaseFunction import BaseFunction
    
    
    class Homework(BaseFunction):
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    functions.__ init __.py(自动加载的重要文件)

    ​ 通过pkgutil包的iter_modules方法找到functions包中的所有python文件(模块),然后加载这些模块,并通过内置方法__dir__()来找到该模块中的所有方法和类名,随后通过getattr()方法获取到可用的类对象组成功能列表,供分配器使用

    import pkgutil
    from functions.BaseFunction import BaseFunction
    
    # 定义功能列表,供分配器调用
    fun_list = []
    # 利用包管理组件循环遍历出指定路径下的所有python文件,返回一个三元元组(文件查询器,文件名,是否为包)
    for file_finder, name, ispkg in pkgutil.iter_modules(__path__):
        # 通过文件查询器和当前文件名找到该python脚本,并加载到变量fun中
        fun = file_finder.find_module(name).load_module(name)
        # 通过__dir__()找到该脚本中所有的方法和类名,包括所有以双下划线开头的方法
        for attr_name in fun.__dir__():
            # 排除掉系统方法
            if "__" in attr_name:
                continue
            # 排除掉所有功能的父类
            if "BaseFunction" in attr_name:
                continue
            # 通过getattr获取到这个方法或类
            attr = getattr(file_finder.find_module(name).load_module(name), attr_name)
            # 抛弃类型为function的方法
            if type(attr) == type:
                # 遍历该类的所有父类,如果继承了BaseFunction则添加到功能列表
                for parent in attr.__bases__:
                    if parent == BaseFunction:
                        fun_list.append(attr)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    text.py
    from functions import fun_list
    
    print(fun_list)
    
    
    def distributor():
        for fun in fun_list:
            res = fun().run()
            if res:
                print("返回数据", res)
                return
        print("未找到对应功能")
        return
    
    
    distributor()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    第二步,测试
    运行text.py

    image-20221102151125927

    [<class 'CurriculumFunction.Curriculum'>, <class 'HomeworkFunction.Homework'>]
    返回数据 查询到课表
    
    • 1
    • 2
    将Curriculum的run方法置空,改变Homework类

    修改后的Homework

    class Homework(BaseFunction):
    
        def run(self):
            return "查询到未做的作业!"
    
        __instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance:
                cls.__instance = object.__new__(cls)
            return cls.__instance
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    重新运行

    image-20221102151419310

    [<class 'CurriculumFunction.Curriculum'>, <class 'HomeworkFunction.Homework'>]
    返回数据 查询到未做的作业!
    
    • 1
    • 2
    将Curriculum和Homework的run方法都置空

    ​ 结果

    image-20221102151634614

    [<class 'CurriculumFunction.Curriculum'>, <class 'HomeworkFunction.Homework'>]
    未找到对应功能
    
    • 1
    • 2
  • 相关阅读:
    java double类型 向上取整,向下取整,四舍五入
    下面我们将介绍二叉树的一些基本操作,包括创建二叉树、插入节点、查找节点、删除节点、遍历二叉树等
    python:关于函数内 * 和 / 是什么意思?
    计算机组成原理知识总结(八)输入/输出系统
    【算法】二分查找-20231121
    设计模式(十)—— 外观模式
    域控制器BSP开发工程师面试题
    Microsoft的PromptBench可以做啥?
    spark3使用hive zstd压缩格式总结
    VMware16以及Ubuntu1.6的下载安装配置详细教程
  • 原文地址:https://blog.csdn.net/weixin_45634261/article/details/127652491