首页 > 编程语言 >python利用依赖注入实现模块解耦

python利用依赖注入实现模块解耦

时间:2023-12-06 20:34:53浏览次数:52  
标签:依赖 obj name get python DataMgr 模块 import

python不是编译型语言, 比较容易出现循环依赖的情况, 比如模块A依赖模块B, 而模块B反过来依赖模块A. 当然可以通过重构解决此问题, 比如合并此两个模块. 但是还有一些技术可以帮助实现解耦. 比如之前我写过的基于消息的机制, 把模块间的依赖转换为对消息的依赖. 本文章介绍另外一种技术: 依赖注入.
关于依赖注入的开源库有不少, 比如:
https://github.com/google/pinject
https://github.com/python-injector/injector
https://github.com/ets-labs/python-dependency-injector
不过我们可以自己实现一个简单的单例模式, 所以就不用这些开源组件了.
我们的实现代码如下:

from typing import TypeVar

T = TypeVar('T')  # 范型类型

_instances:list[type,object] = {}
'''对象实例字典. key为对象类型, object为对象实例'''

def get_obj_by_type(class_name:T,*args,**kwargs)->T|None:
    '''获得指定类型的对象全局单例. args和kwargs为对象所需的参数. 如果创建对象失败, 返回None'''
    #if not hasattr(class_name, '_is_single_sevice'): raise Exception('20231205_1216: 类必须设置单例属性.')
    if class_name not in _instances:
        try: _instances[class_name] = class_name(*args,**kwargs)
        except: return None
    return _instances[class_name]

def single_sevice(cls:T)->T:
    '''单例装饰器. 装饰类, 使其成为全局单例'''
    cls._is_single_sevice:bool = True  # 设置为单例服务
    return cls

def get_obj(module_name:str,class_name:str,*args,**kwargs)->object:
    '''获得指定模块的指定类对象. args和kwargs为对象所需的参数. 如果创建对象失败, 返回None'''
    module = __import__(module_name)
    m = getattr(module,class_name)
    return get_obj_by_type(m,*args,**kwargs)

用户有几种用法:

  • 根据类型获得对象
from DataMgr import DataMgr
from my_injector import get_obj_by_type
obj = get_obj_by_type(DataMgr)
obj.run()

这种方式比较简单直接, 并且支持类型提示和自动补全, 但是显式依赖于被调用模块, 仍可能造成循环依赖.

  • 根据模块名和类名获得对象
obj = get_obj('DataMgr','DataMgr')
obj.run()

这种方式比较简单粗暴, 不显式依赖服务组件, 但是不支持类型提示和代码补全.

  • 结合什么两种模式的优点, 提供服务封装
from __future__ import annotations
from typing import TYPE_CHECKING
from my_injector import get_obj

if TYPE_CHECKING:
    from DataMgr import DataMgr
    from OperateUnit import UnitMgr

def get_DataMgr()->DataMgr: return get_obj('DataMgr','DataMgr')
def get_UnitMgr()->UnitMgr: return get_obj('OperateUnit','UnitMgr')

由于使用了TYPE_CHECKING技术, 既支持类型提示有不真的依赖于被调用组件. 用户可以在任何地方放心使用类似get_DataMgr().run()的代码即可.

这样, 结合消息模式和依赖注入技术, 可以最大限度的减少python模块间的依赖, 使代码更容易开发和维护.

标签:依赖,obj,name,get,python,DataMgr,模块,import
From: https://www.cnblogs.com/huzhongqiang/p/17880139.html

相关文章

  • python assert用法
    python中assert用法。具体分析如下1、assert语句用来声明某个条件是真的。2、如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。3、当assert语句失败的时候,会引发一AssertionEr......
  • buuctf 加固题 babypython WriteUp
    原题wp参考链接:https://www.cnblogs.com/karsa/p/13529769.html这是CISCN2021总决赛的题,解题思路是软链接zip读取文件,然后伪造admin的session读取flag回到buuctf的这个题:ssh连上去,查看文件/app/y0u_found_it/y0u_found_it_main.py关键代码:random.seed(uuid.getnode())a......
  • Python中级之深浅拷贝
    深浅拷贝Python源码对深浅拷贝的解释以下来源于Python源码中对copy的解释#英文原文Thedifferencebetweenshallowanddeepcopyingisonlyrelevantforcompoundobjects(objectsthatcontainotherobjects,likelistsorclassinstances).-Ashallowcopyco......
  • Python中级之列表字典推导式和三元运算符
    列表生成式列表生成式是一种在Python中用于创建列表的简洁和优雅的语法。它允许你使用一行代码生成一个新的列表,而不必使用传统的循环语句。以下是列表生成式的基本语法:[expressionforiteminiterableifcondition]expression:用于生成新列表中每个元素的表达式。ite......
  • @SpringBootTest 和 @RunWith 注解不能识别 单元测试第一步引入maven依赖
    @SpringBootTest和@RunWith注解不能识别单元测试第一步引入maven依赖一、背景    最近在预研 Rocketmq,在写小例子的时候,需要编写测试代码,突然间发现我的 @SpringBootTest 和 @RunWith 这两个注解不能识别,于是展开了我的问题排查过程。问题截图如下:二、问题排......
  • 【python入门之异常处理】---python 异常处理
    title:【python入门之异常处理】---python异常处理date:2023-12-0619:14:26updated:2023-12-0619:40:00description:【python入门之异常处理】---python异常处理cover:https://home.cnblogs.com/u/dream-ze/【一】什么是异常异常是程序运行时可能发......
  • python中for循环用法
    1、在python中完整的for语法如下#for变量in集合:#循环代码#else:#没有通过的break退出循环,结束后会执行代码2、应用场景在迭代变量嵌套的数据类型时,列表【数组】中包括多个字典【键值对存放的值:用{key:value}】需求:要判断某一个字典中是否存在......
  • python入门之深浅拷贝】---python 深浅拷贝
    title:【python入门之深浅拷贝】---python深浅拷贝date:2023-12-0618:54:06updated:2023-12-0619:20:00description:【python入门之深浅拷贝】---python深浅拷贝cover:https://zhuanlan.zhihu.com/p/631965597https://home.cnblogs.com/u/dream-ze/【......
  • # yyds干货盘点 # 分享一个Python网络爬虫数据采集利器
    前言你是否曾为获取重要数据而感到困扰?是否因为数据封锁而无法获取所需信息?是否因为数据格式混乱而头疼?现在,所有这些问题都可以迎刃而解。让我为大家介绍一款强大的数据收集平台——亮数据BrightData。作为世界领先的数据收集平台,亮数据以其高效、可靠和灵活的方式检索提取关键的......
  • [Python急救站]火车购票程序
    火车购票程序如果要一直执行程序,加个while循环即可。要是要智能判断月份,可以通过调取当前时间进行判断即可。print("""1、每年的1-3月和7-9月凭学生证可以打5折。2、10人(含10人)以上团购还可以打9折。""")i=eval(input("请输入单张火车票的全价:(1~1000):"))a=input("是否为......