2024-05-29 03:47:51 发布
网友
最近我读了很多关于python的文章,所以我的问题是
How to do dependency injection python-way?
我指的是通常的场景,例如,服务A需要访问UserService进行授权检查。
我最近发布了一个python的DI框架,可能对您有所帮助。我认为这是一个相当新的看法,但我不确定它是如何'Python'。你自己判断吧。欢迎反馈。
https://github.com/suned/serum
这要看情况而定。例如,如果将依赖项注入用于测试目的(因此可以很容易地模拟出某些内容),则通常可以完全放弃注入:相反,可以模拟出要注入的模块或类:
subprocess.Popen = some_mock_Popen result = subprocess.call(...) assert some_mock_popen.result == result
subprocess.call()将调用subprocess.Popen(),我们可以模拟它,而不必以特殊方式注入依赖项。我们可以直接替换subprocess.Popen。(这只是一个例子;在现实生活中,你会以一种更加稳健的方式来做这件事。)
subprocess.call()
subprocess.Popen()
subprocess.Popen
如果在更复杂的情况下使用依赖注入,或者当模拟整个模块或类不合适时(例如,因为您只想模拟一个特定的调用),那么使用类属性或模块全局变量作为依赖项是通常的选择。例如,考虑一个my_subprocess.py:
my_subprocess.py
from subprocess import Popen def my_call(...): return Popen(...).communicate()
通过分配给my_subprocess.Popen,您可以很容易地只替换my_call()发出的Popen调用;它不会影响对subprocess.Popen的任何其他调用(当然,它会替换对my_subprocess.Popen的所有调用)
my_subprocess.Popen
my_call()
Popen
class MyClass(object): Popen = staticmethod(subprocess.Popen) def call(self): return self.Popen(...).communicate(...)
在使用此类类属性时(考虑到选项很少需要此类属性),应注意使用staticmethod。如果不这样做,并且要插入的对象是一个普通的函数对象或另一种类型的描述符(如属性),当从类或实例中检索时,它会做一些特殊的事情,它会做错误的事情。更糟糕的是,如果您现在使用的不是一个描述符(比如示例中的subprocess.Popen类),那么它现在就可以工作,但是如果所讨论的对象将来更改为一个普通函数,那么它将混乱地断开。
staticmethod
最后,只有简单的回调;如果只想将类的特定实例绑定到特定服务,可以将服务(或服务的一个或多个方法)传递给类初始值设定项,并让它使用:
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(...)
当设置这样的实例属性时,您不必担心描述符的触发,所以只分配函数(或类或其他可调用或实例)就可以了。
这个“仅限setter”注射配方怎么样? http://code.activestate.com/recipes/413268/
这是一种非常恶毒的行为,使用带有__get__()/__set__()的“描述符”协议,但是相当有攻击性,需要用一个RequiredFeature实例替换所有属性设置代码,该实例用所需的Feature的str名称初始化。
__get__()
__set__()
RequiredFeature
Feature
我最近发布了一个python的DI框架,可能对您有所帮助。我认为这是一个相当新的看法,但我不确定它是如何'Python'。你自己判断吧。欢迎反馈。
https://github.com/suned/serum
这要看情况而定。例如,如果将依赖项注入用于测试目的(因此可以很容易地模拟出某些内容),则通常可以完全放弃注入:相反,可以模拟出要注入的模块或类:
subprocess.call()
将调用subprocess.Popen()
,我们可以模拟它,而不必以特殊方式注入依赖项。我们可以直接替换subprocess.Popen
。(这只是一个例子;在现实生活中,你会以一种更加稳健的方式来做这件事。)如果在更复杂的情况下使用依赖注入,或者当模拟整个模块或类不合适时(例如,因为您只想模拟一个特定的调用),那么使用类属性或模块全局变量作为依赖项是通常的选择。例如,考虑一个
my_subprocess.py
:通过分配给
my_subprocess.Popen
,您可以很容易地只替换my_call()
发出的Popen
调用;它不会影响对subprocess.Popen
的任何其他调用(当然,它会替换对my_subprocess.Popen
的所有调用)在使用此类类属性时(考虑到选项很少需要此类属性),应注意使用
staticmethod
。如果不这样做,并且要插入的对象是一个普通的函数对象或另一种类型的描述符(如属性),当从类或实例中检索时,它会做一些特殊的事情,它会做错误的事情。更糟糕的是,如果您现在使用的不是一个描述符(比如示例中的subprocess.Popen
类),那么它现在就可以工作,但是如果所讨论的对象将来更改为一个普通函数,那么它将混乱地断开。最后,只有简单的回调;如果只想将类的特定实例绑定到特定服务,可以将服务(或服务的一个或多个方法)传递给类初始值设定项,并让它使用:
当设置这样的实例属性时,您不必担心描述符的触发,所以只分配函数(或类或其他可调用或实例)就可以了。
这个“仅限setter”注射配方怎么样? http://code.activestate.com/recipes/413268/
这是一种非常恶毒的行为,使用带有
__get__()
/__set__()
的“描述符”协议,但是相当有攻击性,需要用一个RequiredFeature
实例替换所有属性设置代码,该实例用所需的Feature
的str名称初始化。相关问题 更多 >
编程相关推荐