在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中没有被广泛使用。
我认为由于python的动态特性,人们并不经常看到对另一个动态框架的需求。当一个类继承了new-style 'object'时,你可以动态地创建一个新变量(https://wiki.python.org/moin/NewClassVsClassicClass)。
即。
在普通python中:
#application.py
class Application(object):
def __init__(self):
pass
#main.py
Application.postgres_connection = PostgresConnection()
#other.py
postgres_connection = Application.postgres_connection
db_data = postgres_connection.fetchone()
不过,看看https://github.com/noodleflake/pyioc,这可能就是你要找的。
即pyioc
from libs.service_locator import ServiceLocator
#main.py
ServiceLocator.register(PostgresConnection)
#other.py
postgres_connection = ServiceLocator.resolve(PostgresConnection)
db_data = postgres_connection.fetchone()
我支持“Jörg W Mittag”的回答:“DI/IoC的Python实现是如此的轻量级,以至于它完全消失了”。
为了支持这一说法,看看Martin Fowler从Java移植到Python的著名示例:Python:Design_Patterns:Inversion_of_Control
从上面的链接中可以看到,Python中的“Container”可以用8行代码编写:
class Container:
def __init__(self, system_data):
for component_name, component_class, component_args in system_data:
if type(component_class) == types.ClassType:
args = [self.__dict__[arg] for arg in component_args]
self.__dict__[component_name] = component_class(*args)
else:
self.__dict__[component_name] = component_class
我并不认为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编程语言和他关于这个主题的文章:
被认为有害的构造物
注射
禁止进口(续)