Python依赖注入

时间:2015-11-30 01:07:07

标签: python dependency-injection

我有3个模块:A,B,C

A contains a set of classes that B has fetchers for.

B contains a bunch of singletons that just deal with caching created objects and providing them when requested. Essentially just fetchers.

C is a list of functions that requires instances of A. 

我需要做的操作是:

C::SomeFunc():
   B.getInstance("instance ID")


B::getInstance(someID: str) -> A:
   -look at cache, which is either [] or {}
   -if it is in cache, return that, else do:  A(someID)

我的问题是,你将如何绕过这些模块的实例?这个问题的主要动机是我对Python的内存分配系统缺乏了解。

我可以按照基于构造函数的依赖注入的方式做一些事情来获取他们需要去的A,B,C的实例,然后有一些“master / god / controller”对象只传递他们的东西需要去 -

例如:

class god(object):
    def __init__(self):
        a = A()
        b = B()
        c = C(b)
.....
.....
class C(object):
    def __init__(self, B_instance):
         self.B = B_instance
    def SomeFunc(self, instanceID):
         self.B.getInstance(instanceID)

但这似乎是一个黑客。

有什么建议吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

我已经看到了一些在there on PyPI上提供实例提供程序的软件包,如果这就是您要查找的内容。就个人而言,我不想处理另一个对象来获取实例。所以我为此创建了自己的库(仅限Python 3)。您只需要 @inject 和注释。

from py3njection import inject
from some_package import ClassToInject

class Demo:
    @inject
    def __init__(self, object_to_use: ClassToInject):
        self.dependency = object_to_use

demo = Demo()

你可以找到它here。 它每次调用方法时基本上都会生成一个新实例。

测试很简单,因为你只需要将mocks作为参数传递给unittest你的函数/方法。

我也添加了 @singleton

如果您需要更多的实例化方法,例如您正在描述的缓存系统,那么文档将解释如何轻松实现您自己的实例。所有与缓存相关的内容都将在工厂中处理,依赖于它们的对象不必知道如何获取它们。

但是如果您使用的是Python 2,或者您需要对注射有更多控制权,this could work too。但你仍然需要操纵提供者。

答案 1 :(得分:0)

我最近发布了一个可以帮助您实现这一目标的小型库。反馈非常受欢迎:D

https://github.com/suned/serum

答案 2 :(得分:0)

@autowired是另一个Python 3装饰器,可以实现轻松,干净的依赖注入:

  • 该功能无需了解所有
  • 的自动装配
  • 依赖关系可以延迟初始化
  • 如果需要,调用者可以显式传递依赖项实例

转动代码

def __init__(self, *, model: Model = None, service: Service = None):
    if model is None:
        model = Model()

    if service is None:
        service = Service()

    self.model = model
    self.service = service
    # actual code

进入

@autowired
def __init__(self, *, model: Model, service: Service):
    self.model = model
    self.service = service
    # actual code

没有复杂的东西,没有设置,没有强制执行工作流程。

装饰者的方法很简约。可能是一个完整的框架更适合你的情况。为此,有一些优秀的模块,如Injector