如何用python方式进行依赖注入?

2024-05-29 03:47:51 发布

您现在位置:Python中文网/ 问答频道 /正文

最近我读了很多关于python的文章,所以我的问题是

How to do dependency injection python-way?

我指的是通常的场景,例如,服务A需要访问UserService进行授权检查。


Tags: to文章场景dependencydowayhowinjection
3条回答

我最近发布了一个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。(这只是一个例子;在现实生活中,你会以一种更加稳健的方式来做这件事。)

如果在更复杂的情况下使用依赖注入,或者当模拟整个模块或类不合适时(例如,因为您只想模拟一个特定的调用),那么使用类属性或模块全局变量作为依赖项是通常的选择。例如,考虑一个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(...)

当设置这样的实例属性时,您不必担心描述符的触发,所以只分配函数(或类或其他可调用或实例)就可以了。

这个“仅限setter”注射配方怎么样? http://code.activestate.com/recipes/413268/

这是一种非常恶毒的行为,使用带有__get__()/__set__()的“描述符”协议,但是相当有攻击性,需要用一个RequiredFeature实例替换所有属性设置代码,该实例用所需的Feature的str名称初始化。

相关问题 更多 >

    热门问题