python 3的依赖注入库
serum的Python项目详细描述
生成状态
生成状态:
代码质量:
说明
<代码>血清< /代码>是Python 3中一个新的依赖依赖注入。
<代码>血清< /代码>为纯Python,无依赖关系。
安装
> pip install serum
快速启动
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
文档
注入
inject
用于修饰要在其中注入的函数和类
依赖关系。
fromserumimportinject,dependency@dependencyclassMyDependency:pass@injectdeff(dependency:MyDependency):assertisinstance(dependency,MyDependency)f()
用inject
修饰的函数可以作为普通函数调用。<代码>血清< /代码>
不尝试在调用时插入给定的参数。
@injectdeff(dependency:MyDependency):print(dependency)f('Overridden dependency')# outputs: Overridden dependency
inject
将实例化用依赖项修饰的类。在
这样,就可以使用inject
和
依赖关系
简单类型和对象的实例可以是
使用关键字参数注入到上下文
@injectdeff(dependency:str):assertdependency=='a named dependency'withContext(dependency='a named dependency'):f()
inject
也可用于修饰类。
@injectclassSomeClass:dependency:MyDependency
这大致相当于:
classSomeClass:@injectdef__init__(self,dependency:MyDependency):self.__dependency=dependency@propertydefdependency(self)->MyDependency:returnself.__dependency
可以重写指定为类级批注的依赖项 使用关键字参数来初始化
assertSomeClass(dependency='Overridden!').dependency=='Overridden!'
依赖关系
用依赖关系修饰的类可以被实例化和注入
按<代码>血清< /代码>
fromserumimportdependency,inject@dependencyclassLog:definfo(self,message):print(message)@injectclassNeedsLog:log:Logassertisinstance(NeedsLog().log,Log)
<代码>血清< /代码>依赖于能够为<代码>依赖项装饰类注入所有依赖项
递归地。为了实现这一点,<代码>血清< /代码>假定<代码>
可以在不带任何参数的情况下调用of 注意,循环依赖关系阻止了 在 您可以使用关键字参数提供任何类型的命名依赖项。 若要始终在同一 注意 <代码>血清<代码>支持从构建中注入<代码> MAICICMOK < /代码> s
注意, 导入一些 最后,在项目的根目录中创建一个名为 ipython现在将在
每个repl会话都在项目的根目录中启动。 如果你一直在研究python的依赖注入框架,
毫无疑问,您会遇到这样的意见: 在python中不需要依赖注入。
你可以用鸭子打字和猴子修补! 这句话背后的立场通常是你只需要依赖
以静态类型语言注入。 实际上,在任何语言中都不需要依赖注入,
静态类型的或其他类型的。
然而,当构建需要在多个环境中运行的大型应用程序时,
依赖注入可以让你的生活更轻松。以我的经验,
过度使用猴子补丁来管理环境会导致混乱
隐式初始化步骤混乱,如果值为none,则输入代码。 除了作为一个框架外,我还尝试设计<代码>血清<代码>
设计遵循依赖倒置原则的类: 一个人应该"依赖抽象,而不是具体化。" 这是通过让继承成为提供
依赖关系并允许依赖关系是抽象的。dependency
修饰类。
这意味着必须使用inject
注入依赖项的
\uu init
的所有参数
0
> pip install serum
依赖关系的实例化
类导致错误。
1
> pip install serum
上下文
上下文提供依赖项的实现。a
上下文
请求类型的特定子类型(按方法解析顺序)。
2
> pip install serum
上下文中插入一个类型是错误的,该上下文提供该类型的两个或多个同等特定的子类型:
3
> pip install serum
上下文也可以用作装饰口服补液盐:< >
4
> pip install serum
5
> pip install serum
上下文对每个线程都是本地的。这意味着当使用多线程时
每个线程都在自己的上下文中运行
6
> pip install serum
singleton
上下文中插入依赖项的同一实例,请使用
singleton
注释类型。
7
> pip install serum
singleton
在不同环境中注入的依赖项
不会引用同一实例。
8
> pip install serum
模拟
unittest.mock使用
mock
实用程序的unittests中的库
功能。模拟被重置
当环境上下文关闭时。
9
> pip install serum
mock
使用其参数指定注入的magicmock
实例。这意味着
试图调用未由模拟组件定义的方法
导致错误fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
0
mock
将只模拟
作为其参数提供的确切类型,但不是
或多或少的特定类型fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
1
匹配
match
是用于匹配上下文的小型实用函数
使用环境变量的值。
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
2
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
3
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
4
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
5
IPython集成
上下文并将其作为
每个ipython会话开始时的上下文管理器。
此外,您经常希望在特殊的上下文中运行ipython repl,
例如,提供通常通过命令行提供的配置
以其他方式争论。
ipython_config.py中:
:fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
6
ipython_context.py
的文件。在里面,
将要自动启动的上下文
实例分配给全局
名为context的变量
fromserumimportinject,dependency,Context# Classes decorated with 'dependency' are injectable types.@dependencyclassLog:definfo(self,message:str):raiseNotImplementedError()classSimpleLog(Log):definfo(self,message:str):print(message)classStubLog(SimpleLog):definfo(self,message:str):pass@inject# Dependencies are injected using a class decorator...classNeedsLog:log:Log# ...and class level annotations...classNeedsSimpleLog:@inject# ...or using a function decoratordef__init__(self,log:SimpleLog):self.log=log@injectclassNeedsNamedDependency:named_dependency:str# class level annotations annotated with a type that is not# decorated with 'dependency' will be treated as a named# dependency# Contexts provide dependencieswithContext(SimpleLog,named_dependency='this name is injected!'):assertisinstance(NeedsLog().log,SimpleLog)assertNeedsNamedDependency().named_dependency=='this name is injected!'# Contexts will always provide the most specific # subtype of the requested type. This allows you to change which# dependencies are injected.withContext(StubLog):NeedsLog().log.info('Hello serum!')# doesn't output anythingNeedsSimpleLog().log.info('Hello serum!')# doesn't output anything
7
推荐PyPI第三方库