我最近一直在阅读很多关于
python的方式,所以我的问题是
How to do dependency injection python-way?
我正在谈论通常的情况,例如,服务A需要访问UserService进行授权检查.
这一切都取决于情况.例如,如果您使用依赖注入来进行测试,所以您可以轻松地嘲笑某些内容 – 您可以经常放弃注入:您可以嘲笑您将注入的模块或类:
subprocess.Popen = some_mock_Popen result = subprocess.call(...) assert some_mock_popen.result == result
subprocess.call()将调用subprocess.Popen(),我们可以模拟它,而不必以特殊的方式注入依赖.我们可以直接替换subprocess.Popen. (这只是一个例子;在现实生活中,你会以更加健壮的方式做到这一点)
如果对更复杂的情况使用依赖注入,或者模拟整个模块或类不适用(因为例如,您只想嘲弄一个特定的调用),则使用类属性或模块全局变量作为依赖项是通常的选择.例如,考虑到一个my_subprocess.py:
from subprocess import Popen def my_call(...): return Popen(...).communicate()
您只能通过分配给my_subprocess.Popen来轻松替换由my_call()创建的Popen调用;它不会影响任何其他调用subprocess.Popen(但它会替换所有调用my_subprocess.Popen,当然).类似地,类属性:
class MyClass(object): Popen = staticmethod(subprocess.Popen) def call(self): return self.Popen(...).communicate(...)
当使用这样的类属性时,考虑到这些选项很少需要,你应该注意使用staticmethod.如果不这样做,并且您插入的对象是一个正常的函数对象或另一种类型的描述符,就像一个属性,在从类或实例中检索到时,会执行一些特殊的描述,它会做错事.更糟糕的是,如果你现在使用的东西不是一个描述符(比如subprocess.Popen类,在这个例子中),它现在就可以工作,但是如果有问题的对象改变了一个正常的功能,那么它将会令人困惑.
最后,只有简单的回调;如果您只想将特定实例的类绑定到特定的服务,则可以将服务(或一项或多项服务的方法)传递给类初始化程序,并使用它:
class MyClass(object): def __init__(self,authenticate=None,authorize=None): if authenticate is None: authenticate = default_authenticate if authorize is None: authorize = default_authorize self.authenticate = authenticate self.authorize = authorize def request(self,user,password,action): self.authenticate(user,password) self.authorize(user,action) self._do_request(action) ... helper = AuthService(...) # Pass bound methods to helper.authenticate and helper.authorize to MyClass. inst = MyClass(authenticate=helper.authenticate,authorize=helper.authorize) inst.request(...)