yadi——又一个依赖注入框架

yadi-framework的Python项目详细描述


build statusPypi

亚迪

又一个依赖注入框架

yadi是一个依赖注入框架。它同时支持类和 以声明的方式运行。

安装

pip install yadi-framework

基本示例

这是一个简单的注射示例:

fromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinjectfromyadi.typesimportYadi@inject()classComponent1:pass@inject()classComponent2:def__init__(self,c1:Yadi[Component1]):self.c1=c1@inject()classComponent3:def__init__(self,c1:Yadi[Component1]):self.c1=c1c2=DEFAULT_CONTEXT.get_bean(Component2)# type: Component2c3=DEFAULT_CONTEXT.get_bean(Component3)# type: Component3print(Component1istype(c2.c1))# Trueprint(c2.c1isc3.c1)# True

下面是一个如何注入函数的示例:

fromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinjectfromyadi.typesimportYadi@inject()classComponent:pass@inject(name='another_function')defh(x,y,z=None):assertisinstance(x,Component)print('Function h:',type(x))@inject(name='my_function')deff(a:Yadi[Component],b,c:Yadi['another_function']=None,d:str=None):c(a,b,z=d)DEFAULT_CONTEXT.get_bean('my_function')(23,d=5)# Function h: <class '__main__.Component'>

范围

默认情况下,所有bean都保存为singleton。每一个单子都是 存储在其上下文中,即每个实例都有一个实例。 上下文实例

或者,可以将bean保存为原型,即 每当引用bean时都会生成不同的实例。

fromyadiimportcontextfromyadiimporttypesfromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinject@inject(scope=context.PROTOTYPE,name='a component 1')classComponent1:pass@inject(name='a component 2')classComponent2:def__init__(self,f1:types.Yadi[Component1],f2:types.Yadi['a component 1']):self.f1,self.f2=f1,f2@inject(name='a component 3')classComponent3:def__init__(self,f1:types.Yadi[Component1],f2:types.Yadi['a component 1']):self.f1,self.f2=f1,f2c2=DEFAULT_CONTEXT.get_bean('a component 2')# type: Component2c3=DEFAULT_CONTEXT.get_bean('a component 3')# type: Component3print(isinstance(c2.f1,Component1))# Trueprint(isinstance(c2.f2,Component1))# Trueprint(isinstance(c3.f1,Component1))# Trueprint(isinstance(c3.f2,Component1))# Trueprint(c2.f1==c2.f2)# Falseprint(c3.f1==c3.f2)# Falseprint(c2.f1==c3.f1)# Falseprint(c2.f1==c3.f2)# Falseprint(c2.f2==c3.f1)# Falseprint(c2.f2==c3.f2)# False

还可以定义自定义范围并将其添加到上下文中。

这里是线程本地作用域的一个示例:

importthreadingfromyadi.contextimportScopefromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinjectclassThreadLocalScope(Scope):def__init__(self):self._tl=threading.local()defget(self,key:str):returngetattr(self._tl,key,None)defset(self,key:str,obj:object):setattr(self._tl,key,obj)@propertydefname(self):return'threadlocal'@propertydeflevel(self):return100DEFAULT_CONTEXT.add_scope(ThreadLocalScope())@inject(scope='threadlocal',name='a component 1')classComponent1:passc1=DEFAULT_CONTEXT.get_bean('a component 1')c1_2=DEFAULT_CONTEXT.get_bean('a component 1')thread_c1=[]c1_t=Nonedef_f():globalc1_tc1_t=DEFAULT_CONTEXT.get_bean('a component 1')print(c1_t==DEFAULT_CONTEXT.get_bean('a component 1'))# Truethread_c1.append(c1_t)t=threading.Thread(target=_f)t.start()t.join()print(c1==c1_2)# Trueprint(c1==c1_t)# False

^ {STR 1 } $作用域代理< /强>

假设在单例中注入一个线程本地作用域bean。作为一个 结果,共享同一个单例的不同线程不应共享 同一线程本地bean,这是不可能的。

为了解决这个问题,yadi在注入的 在上下文中委托对当前bean的任何访问的bean。

一般来说,作用域有一个level属性:如果注入的bean 具有比容器bean更高的作用域级别,注入的bean是 包装到作用域代理中。

这是一个范围代理的例子(不用担心,你不必 做任何事来让它工作)。

importrandomimportthreadingfromyadi.bean_factoriesimport_ScopedProxyfromyadi.contextimportScopefromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinjectfromyadi.typesimportYadiclassThreadLocalScope(Scope):def__init__(self):self._tl=threading.local()defget(self,key:str):returngetattr(self._tl,key,None)defset(self,key:str,obj:object):setattr(self._tl,key,obj)@propertydefname(self):return'threadlocal'@propertydeflevel(self):return100DEFAULT_CONTEXT.add_scope(ThreadLocalScope())@inject(scope='threadlocal')classComponent1:def__init__(self):self.object_id=random.randint(0,1000000)@inject(name='a component')classComponent2:def__init__(self,f1:Yadi[Component1]):self.f1=f1component=DEFAULT_CONTEXT.get_bean('a component')component_thread_id=[]print('Main thread, scoped proxy type',type(component.f1)==_ScopedProxy)# Main thread, scoped proxy type Truedef_f():component_thread=DEFAULT_CONTEXT.get_bean('a component')print('Subthread, scoped proxy type',type(component_thread.f1)==_ScopedProxy)component_thread_id.append(component_thread.f1.object_id)print('Subthread, bean id',component_thread.f1.object_id==DEFAULT_CONTEXT.get_bean('a component').f1.object_id)t=threading.Thread(target=_f)t.start()t.join()# Subthread, scoped proxy type True# Subthread, bean id Trueprint('Main thread, bean id',component.f1.object_id==component_thread_id[0])# Main thread, bean id False

上下文

所有组件都保存在上下文中。

默认情况下,injectdecorator将bean实例保存在 yadi.context_impl.DEFAULT_CONTEXT

您可能希望实例化一个新上下文并将其作为^{tt4}传递$ injectdecorator的关键字参数。

生命周期

只要创建一个bean,就可以触发它们。在 为了定义要触发的方法,必须修饰 它们带有post_create,如下所示:

fromyadi.context_implimportDEFAULT_CONTEXTfromyadi.decoratorsimportinject,post_createfromyadi.typesimportYadi@inject()classComponent1:pass@inject()classComponent2:def__init__(self,c1:Yadi[Component1]):self.c1=c1self.invoked_post_create=0@post_createdeffinished_creating(self):print('Component 1:',self.c1)# Component 1: <__main__.Component1 object at 0x7f42e90d2e48>self.invoked_post_create+=1component_2=DEFAULT_CONTEXT.get_bean(Component2)# type: Component2print('post_create invokations:',component_2.invoked_post_create)# post_create invokations: 1DEFAULT_CONTEXT.get_bean(Component2)print('post_create invokations:',component_2.invoked_post_create)# post_create invokations: 1

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java我的计时器(scheduleAtFixedRate)不循环   如何在Java中实现过滤迭代器?   java如何在不从本地xml、csv文件访问API的情况下将变量发布到php站点?   SuiteClasses语法的Java JUnit类数组   java从URLConnection读取二进制文件   java在Android Studio中发送加密文本时失败   Android:最近最少使用(LRU)算法在java中的实现?   java Selenium WebDriver无法打开Firefox配置文件   java如何处理带有嵌套抽象类的GSON?   java类型通知的方法SetLateStevenInfo(GcmMessageHandler,String,String,PendingContent)未定义   java Apple或Mac Mail会打开所有附件图像,即使它们已嵌入   java如何解析下面的xml代码?   java如何创建特定于API级别的UI(针对平板电脑和Android旧版本的不同UI,针对同一应用)?   servlet的通配符路径?