Python 插件式程序设计与开发实践总结

简介: Python 插件式程序设计与开发实践总结

插件式程序设计与开发实践总结


开发环境

win 10

python 3.6.5

 

代码结构

image.png

 

 

 

 

需求描述

如上,以user.py为程序入口脚本,运行该脚本时,需要创建一个user类对象,执行一系列动作(包含一系列动作的列表)。程序执行动作前,要求先获取动作名称,根据该名称,执行不同的操作。这些操作,对应不同的类函数。

 

 

实现思路

大致实现思路就是,把user对象需要运行的类函数(使用@classmethod修饰的函数,可不用创建对象进行调用),当作插件函数,并设置为user的属性,这样程序运行时,可通过该属性来调用对应的类函数。这里的问题是,程序怎么知道执行哪个类函数呢?到目前为止,程序只能根据动作名称来判断待执行的操作,所以,需要建立动作名称和类函数的映射关系。

 

怎么建立动作名称和类函数的映射关系呢?这里用到了装饰器,新建一个装饰器类ActionDecorator,为该类设置一个字典类型的类属性ACTION_FUNC_CLASS_MODULE_MAP,用这个类来存放动作名称和类函数的映射关系。我们把需要当作插件函数的类函数都用该装饰器进行修饰。

 

这里,笔者发现一个特性,就是对应模块被导入时,对应模块,对应类函数如果使用了装饰器,该装饰器函数会被执行。同时,笔者还发现另外一个特性,

首次对某个包执行import操作时,该包下面的__init__.py文件将优先被执行。基于这两个特性,我们把装饰器放在用于管理插件类函数的外围软件包下(例中的components包),同时,在该外围软件包下的__init__.py中加入动态加载插件模块的代码:遍历外围软件包下的所有非__init__.py文件,并且动态加载改模块。这样,当在user.py入口文件中,执行from components.decoraters.action_decorater import ActionDecorator时,会自动执行components/__init__.py文件,动态加载所有插件模块,并且自动触发装饰器的执行,装饰器方法执行,会自动根据提供的方法参数建立动作名称和类函数的映射关系。

 

然后,在初始化user对象时,给该对象动态设置属性,属性名称设置为动作名称,属性值设置为类方法,这样,执行动作时,就可以根据动作名称调用对应的类方法了。

 

 

代码实现

 

 

action_decorate.py

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@CreateTime: 2020/12/09 14:58
@Author : shouke
'''
class ActionDecorator(object):
    '''
    action 装饰器
    '''
    ACTION_FUNC_CLASS_MODULE_MAP = {}
    @classmethod
    def action_register(cls, action, class_name, function_name, module_path):
        def wrapper(func):
            cls.ACTION_FUNC_CLASS_MODULE_MAP.update({action: {'class_name':class_name, 'function_name':function_name, 'module_path':module_path}})
            return func
        return wrapper 

 components/__init__.py

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@Author : shouke
'''
import os.path
import importlib
def load_plugin_modules():
    '''递归加载当前目录下的所有模块'''
    head, tail = os.path.split(__file__)
    package_father_path, package = os.path.split(head)
    def load_modules(dir_path):
        nonlocal package_father_path
        if not os.path.isdir(dir_path):
            return
        for name in os.listdir(dir_path):
            full_path = os.path.join(dir_path, name)
            if os.path.isdir(full_path):
                load_modules(full_path)
            elif not name.startswith('_') and name.endswith('.py'):
                temp_path = full_path.replace(package_father_path, '')
                relative_path = temp_path.replace('\\', '/').lstrip('/').replace('/', '.')
                importlib.import_module(relative_path.rstrip('.py'), package=package)
    load_modules(head)
# 加载模块,自动触发装饰器,获取相关插件函数相关信息
load_plugin_modules()

assertioner.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@Author : shouke
'''
from components.decoraters.action_decorater import ActionDecorator
class Assertioner(object):
    @classmethod
    @ActionDecorator.action_register('assert_equal', 'Assertioner', 'assert_equal', __name__)
    def assert_equal(self,  config:dict, *args, **kwargs):
        print('执行断言')
        print('断言配置:\n', config)

send_request.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@Author : shouke
'''
from components.decoraters.action_decorater import ActionDecorator
class Requester(object):
    @ActionDecorator.action_register('send_request', 'Requester', 'send_request', __name__)
    @classmethod
    def send_request(self, config:dict, *args, **kwargs):
        print('发送请求')
        print('请求配置:')
        print(config)

 

example.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@CreateTime: 2020/12/10 15:51
@Author : shouke
'''
from components.decoraters.action_decorater import ActionDecorator
class CustomClassName(object):
    @ActionDecorator.action_register('custom_action_name', 'CustomClassName', 'action_func_name', __name__)
    @classmethod
    def action_func_name(self, config:dict, *args, **kwargs):
        '''
        example
        user_instance: kwargs['user'] # 压测用户实例
        '''
        # do something you want
# 说明 plugings目录下可自由创建python包,管理插件,当然,也可以位于components包下其它任意位置创建python包,管理插件(不推荐)

user.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@Author : shouke
'''
from components.decoraters.action_decorater import ActionDecorator
class User(object):
    def __init__(self):
        for action, action_map in ActionDecorator.ACTION_FUNC_CLASS_MODULE_MAP.items():
            module = __import__(action_map.get('module_path'), fromlist=['True'])
            class_cls = getattr(module, action_map.get('class_name'))
            setattr(self, action, getattr(class_cls, action_map.get('function_name')))
    def run_actions(self, actions):
        ''' 执行一系列动作 '''
        for step in actions:
            action = step.get('action')
            if hasattr(self, action):
                getattr(self, action)(step, user=self)
if __name__ == '__main__':
    actions = [{
         "action": "send_request",
         "name": "请求登录", #可选配置,默认为None
         "method": "POST",
         "path": "/api/v1/login",
         "body": {
            "account": "shouke",
            "password": "123456"
         },
         "headers": {
             "Content-Type": "application/json"
         }
    },
    {
         "action": "assert_equal",
         "name": "请求响应断言",
         "target": "body",
         "rule": "assert_contain",
         "patterns": ["shouke","token"],
         "logic":"or"
    }]
    User().run_actions(actions)


运行结果

 

发送请求

请求配置:

{'action': 'send_request', 'name': '请求登录', 'method': 'POST', 'path': '/api/v1/login', 'body': {'account': 'shouke', 'password': '123456'}, 'headers': {'Content-Type': 'application/json'}}

执行断言

断言配置:

{'action': 'assert_equal', 'name': '请求响应断言', 'target': 'body', 'rule': 'assert_contain', 'patterns': ['shouke', 'token'], 'logic': 'or'}

 

 

目录
相关文章
|
1月前
|
存储 人工智能 运维
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
199 48
【01】做一个精美的打飞机小游戏,浅尝阿里云通义灵码python小游戏开发AI编程-之飞机大战小游戏上手实践-优雅草央千澈-用ai开发小游戏尝试-分享源代码和游戏包
|
1月前
|
人工智能 Python
【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-分享源代码和游戏包供游玩-记录完整开发过程-用做好的素材来完善鹰击长空1.0.1版本
【02】做一个精美的打飞机小游戏,python开发小游戏-鹰击长空—优雅草央千澈-持续更新-分享源代码和游戏包供游玩-记录完整开发过程-用做好的素材来完善鹰击长空1.0.1版本
56 7
|
4天前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
23 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
4天前
|
人工智能 测试技术 数据处理
通义灵码 2.0 体验报告:Deepseek 加持下的 Python 开发之旅
通义灵码 2.0 体验报告:Deepseek 加持下的 Python 开发之旅
57 11
|
1月前
|
前端开发 搜索推荐 编译器
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
111 34
【01】python开发之实例开发讲解-如何获取影视网站中经过保护后的视频-用python如何下载无法下载的视频资源含m3u8-python插件之dlp-举例几种-详解优雅草央千澈
|
8天前
|
API Python
python泛微e9接口开发
通过POST请求向指定IP的API注册设备以获取`secrit`和`spk`。请求需包含`appid`、`loginid`、`pwd`等头信息。响应中包含状态码、消息及`secrit`(注意拼写)、`secret`和`spk`字段。示例代码使用`curl`命令发送请求,成功后返回相关信息。
30 5
|
2月前
|
IDE 测试技术 开发工具
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
在Python开发中,调试是提升效率的关键技能。本文总结了10个实用的调试方法,涵盖内置调试器pdb、breakpoint()函数、断言机制、logging模块、列表推导式优化、IPython调试、警告机制、IDE调试工具、inspect模块和单元测试框架的应用。通过这些技巧,开发者可以更高效地定位和解决问题,提高代码质量。
333 8
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
|
1月前
|
人工智能 编译器 Python
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
41 0
python已经安装有其他用途如何用hbuilerx配置环境-附带实例demo-python开发入门之hbuilderx编译器如何配置python环境—hbuilderx配置python环境优雅草央千澈
|
2月前
|
数据可视化 算法 数据挖掘
Python量化投资实践:基于蒙特卡洛模拟的投资组合风险建模与分析
蒙特卡洛模拟是一种利用重复随机抽样解决确定性问题的计算方法,广泛应用于金融领域的不确定性建模和风险评估。本文介绍如何使用Python和EODHD API获取历史交易数据,通过模拟生成未来价格路径,分析投资风险与收益,包括VaR和CVaR计算,以辅助投资者制定合理决策。
117 15
|
2月前
|
存储 API 数据库
使用Python开发获取商品销量详情API接口
本文介绍了使用Python开发获取商品销量详情的API接口方法,涵盖API接口概述、技术选型(Flask与FastAPI)、环境准备、API接口创建及调用淘宝开放平台API等内容。通过示例代码,详细说明了如何构建和调用API,以及开发过程中需要注意的事项,如数据库连接、API权限、错误处理、安全性和性能优化等。
167 5

热门文章

最新文章

推荐镜像

更多