在Java中,IoC / DI是一种非常常见的实践,广泛应用于web应用程序、几乎所有可用的框架和Java EE中。另一方面,也有很多大型的Python web应用程序,但除了Zope(我听说它的编码真的很糟糕)之外,IoC在Python世界中似乎并不常见。(如果你认为我是错的,请举一些例子)。

当然,有一些流行的Java IoC框架的克隆可用于Python,例如springpython。但它们似乎都没有被实际使用。至少,我从来没有碰到过Django或sqlalchemy+<插入您最喜欢的wsgi工具箱在这里>的基于web应用程序使用类似的东西。

在我看来,IoC有合理的优势,可以很容易地取代django-default-user-model,但在Python中广泛使用接口类和IoC看起来有点奇怪,而且不»pythonic«。但是也许有人有更好的解释,为什么IoC在Python中没有被广泛使用。


当前回答

我同意@Jorg的观点,在Python中DI/IoC是可能的,更简单,甚至更漂亮。缺少的是支持它的框架,但也有一些例外。举几个我想到的例子:

Django注释允许您将自己的Comment类与自定义逻辑和表单连接起来。(更多信息) Django允许你使用一个自定义Profile对象来附加到你的User模型。这不是完全的IoC,但却是一个很好的方法。就我个人而言,我希望像注释框架那样取代hole User模型。(更多信息)

其他回答

你可以手动使用Python进行依赖注入,但手动方法有其缺点:

大量的样板代码来进行连接。你可以使用Python的动态特性来进行注入,但这样你就失去了IDE的支持(例如,PyCharm中的Ctrl+Space),并且你会使代码更难理解和调试 没有标准:每个程序员都有自己解决相同问题的方法,这导致了重新发明轮子,理解彼此的代码很快就会成为一种痛苦。依赖注入库为插件提供了简单的框架

要做到这一切,我们需要一个依赖注入框架,例如这个https://python-dependency-injector.ets-labs.org/index.html似乎是Python最成熟的依赖注入框架。

对于较小的应用程序,DI容器是不必要的,对于任何有几百行代码或更多的东西,DI容器是必须的,以保持你的代码可维护性。

在我看来,像依赖注入这样的事情是僵化和过于复杂的框架的症状。当代码主体变得过于沉重而难以更改时,你会发现自己不得不选择其中的一小部分,为它们定义接口,然后允许人们通过插入这些接口的对象来改变行为。这很好,但最好在一开始就避免这种复杂性。

这也是静态类型语言的症状。当您必须表达抽象的唯一工具是继承时,那么您几乎到处都在使用继承。话虽如此,c++与之非常相似,但从未像Java开发人员那样对构建器和接口着迷。人们很容易以编写太多泛型代码为代价,实现灵活和可扩展的梦想,而这些代码几乎没有真正的好处。我认为这是文化问题。

通常我认为Python人习惯于为工作选择正确的工具,这是一个连贯而简单的整体,而不是一个真正的工具(带有一千种可能的插件),它可以做任何事情,但提供了令人眼花缭乱的可能配置排列。在必要的地方仍然有可互换的部分,但由于duck-typing的灵活性和语言的相对简单性,不需要定义固定接口的大形式主义。

Django很好地利用了反转控制。例如,由配置文件选择数据库服务器,然后框架向数据库客户机提供适当的数据库包装器实例。

区别在于Python有第一类类型。数据类型(包括类)本身就是对象。如果您想要使用特定的类,只需命名类即可。例如:

if config_dbms_name == 'postgresql':
    import psycopg
    self.database_interface = psycopg
elif config_dbms_name == 'mysql':
    ...

之后的代码可以通过以下方式创建数据库接口:

my_db_connection = self.database_interface()
# Do stuff with database.

与Java和c++需要的样板工厂函数不同,Python只需要一两行普通代码就可以完成。这就是函数式编程与命令式编程的优势所在。

IoC/DI是一个设计概念,但不幸的是,它经常被认为是一个适用于某些语言(或类型系统)的概念。我希望看到依赖注入容器在Python中变得更加流行。有Spring,但它是一个超级框架,似乎是Java概念的直接移植,没有太多考虑“Python方式”。

鉴于Python 3中的注释,我决定尝试一个功能齐全但简单的依赖注入容器:https://github.com/zsims/dic。它基于。net依赖注入容器的一些概念(如果你曾经在那个领域玩过,IMO是很棒的),但与Python概念发生了变化。

似乎人们真的不明白依赖注入和控制反转意味着什么了。

使用控制反转的实践是让类或函数依赖于其他类或函数,但是与其在类或函数代码中创建实例,不如将它们作为参数接收,这样就可以实现松耦合。这有很多好处,如更多的可测试性和实现利斯科夫替换原理。

You see, by working with interfaces and injections, your code gets more maintainable, since you can change the behavior easily, because you won't have to rewrite a single line of code (maybe a line or two on the DI configuration) of your class to change its behavior, since the classes that implement the interface your class is waiting for can vary independently as long as they follow the interface. One of the best strategies to keep code decoupled and easy to maintain is to follow at least the single responsibility, substitution and dependency inversion principles.

What's a DI library good for if you can instantiate an object yourself inside a package and import it to inject it yourself? The chosen answer is right, since java has no procedural sections (code outside of classes), all that goes into boring configuration xml's, hence the need of a class to instantiate and inject dependencies on a lazy load fashion so you don't blow away your performance, while on python you just code the injections in the "procedural" (code outside classes) sections of your code.