介绍
对于Java,依赖注入工作作为纯OOP,即你提供一个接口被实现,在你的框架代码接受实现定义的接口的类的实例。
现在对于Python,你能够做同样的方式,但我认为该方法是太多的开销,在Python的情况下。那么,你将如何实现它的Pythonic方式?
用例
说这是框架代码:
class FrameworkClass(): def __init__(self,...): ... def do_the_job(self,...): # some stuff # depending on some external function
基本方法
最幼稚的(也许最好的?)方法是要求将外部函数提供给FrameworkClass构造函数,然后从do_the_job方法中调用。
框架代码:
class FrameworkClass(): def __init__(self,func): self.func = func def do_the_job(self,...): # some stuff self.func(...)
客户代码:
def my_func(): # my implementation framework_instance = FrameworkClass(my_func) framework_instance.do_the_job(...)
题
问题很短。有没有更好的常用的Pythonic方法来做到这一点?或者支持这样的功能的任何库?
更新:具体情况
想象一下,我开发了一个微型网络框架,它使用令牌处理身份验证。这个框架需要一个函数来提供从令牌获得的一些ID,并获得对应于该ID的用户。
显然,框架不知道关于用户或任何其他应用程序特定逻辑的任何东西,所以客户端代码必须注入用户getter功能到框架中,以使身份验证工作。
有关如何使用超级和多重继承而不是DI的参数,请参见
Raymond Hettinger – Super considered super! – PyCon 2015。如果你没有时间观看整个视频,跳到分钟15(但我建议看看所有)。
以下是一个如何将此视频中所述内容应用于您的示例的示例:
框架代码:
class TokenInterface(): def getUserFromToken(self,token): raise NotImplementedError class FrameworkClass(TokenInterface): def do_the_job(self,...): # some stuff self.user = super().getUserFromToken(...)
客户代码:
class sqlUserFromToken(TokenInterface): def getUserFromToken(self,token): # load the user from the database return user class ClientFrameworkClass(FrameworkClass,sqlUserFromToken): pass framework_instance = ClientFrameworkClass() framework_instance.do_the_job(...)
这将工作,因为Python MRO将保证getUserFromToken客户端方法被调用(如果使用super())。如果你使用Python 2.x,代码将不得不改变。
这里的另一个好处是,如果客户端不提供实现,这将引发异常。
当然,这不是真正的依赖注入,它是多继承和mixins,但它是一个Pythonic的方式来解决你的问题。