在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中没有被广泛使用。


当前回答

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只需要一两行普通代码就可以完成。这就是函数式编程与命令式编程的优势所在。

其他回答

不像Java中的强类型。Python的duck类型行为使得传递对象非常容易。

Java开发人员专注于构造类结构和对象之间的关系,同时保持灵活性。IoC对于实现这一目标非常重要。

Python开发人员专注于完成工作。他们只是在需要的时候把类连接起来。他们甚至不用担心课程的类型。只要它会嘎嘎叫,它就是鸭子!这种性质没有给国际奥委会留下任何余地。

我并不认为DI/IoC在Python中很少见。然而,不常见的是DI/IoC框架/容器。

想想看:DI容器做什么?它允许你

将独立的组件连接成一个完整的应用程序…… ... 在运行时。

我们为“连接在一起”和“在运行时”命名:

脚本 动态

因此,DI容器只是动态脚本语言的解释器。实际上,让我换一种说法:典型的Java/。NET DI容器只是一个蹩脚的解释器,适用于一种非常糟糕的动态脚本语言,语法非常难看,有时是基于xml的。

当您使用Python编程时,为什么要使用一种丑陋、糟糕的脚本语言,而不是拥有一种漂亮、出色的脚本语言呢?实际上,这是一个更普遍的问题:当您使用几乎任何语言进行编程时,当您可以使用Jython和IronPython时,为什么还要使用一种丑陋、糟糕的脚本语言呢?

因此,概括一下:DI/IoC的实践在Python中和在Java中一样重要,原因完全相同。然而,DI/IoC的实现是内置在语言中,并且通常是轻量级的,以至于完全消失了。

(Here's a brief aside for an analogy: in assembly, a subroutine call is a pretty major deal - you have to save your local variables and registers to memory, save your return address somewhere, change the instruction pointer to the subroutine you are calling, arrange for it to somehow jump back into your subroutine when it is finished, put the arguments somewhere where the callee can find them, and so on. IOW: in assembly, "subroutine call" is a Design Pattern, and before there were languages like Fortran which had subroutine calls built in, people were building their own "subroutine frameworks". Would you say that subroutine calls are "uncommon" in Python, just because you don't use subroutine frameworks?)

顺便说一句:关于如何将DI引入逻辑结论的例子,可以看看Gilad Bracha的Newspeak编程语言和他关于这个主题的文章:

被认为有害的构造物 注射 禁止进口(续)

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

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

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

部分原因是模块系统在Python中的工作方式。你可以免费获得一种“单例”,只需从模块中导入它。在模块中定义一个对象的实际实例,然后任何客户端代码都可以导入它,并实际获得一个工作的、完全构造/填充的对象。

这与Java相反,在Java中不导入对象的实际实例。这意味着你总是必须自己实例化它们(或使用某种IoC/DI风格的方法)。您可以通过使用静态工厂方法(或实际的工厂类)来减轻必须自己实例化所有东西的麻烦,但这样您仍然会产生每次实际创建新方法的资源开销。

Haven't used Python in several years, but I would say that it has more to do with it being a dynamically typed language than anything else. For a simple example, in Java, if I wanted to test that something wrote to standard out appropriately I could use DI and pass in any PrintStream to capture the text being written and verify it. When I'm working in Ruby, however, I can dynamically replace the 'puts' method on STDOUT to do the verify, leaving DI completely out of the picture. If the only reason I'm creating an abstraction is to test the class that's using it (think File system operations or the clock in Java) then DI/IoC creates unnecessary complexity in the solution.