为什么IoC/DI在Python中不常见?

2024-05-14 23:22:22 发布

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

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

当然,有几个流行的Java IoC框架的克隆可用于Python,springpython例如。但他们似乎都没有实际应用。至少,我从未遇到过基于Djangosqlalchemy+<insert your favorite wsgi toolkit here>的web应用程序,它使用了类似的东西。

在我看来,IoC有着合理的优势,例如可以很容易地替换django默认用户模型,但是在Python中广泛使用接口类和IoC看起来有点奇怪,而不是“pythonic”。但是也许有人有更好的解释,为什么IoC在Python中没有被广泛使用。


Tags: django代码框架webzope应用程序sqlalchemy世界
3条回答

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

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

  1. 将独立的组件连接到一个完整的应用程序中。。。
  2. 。。。在运行时。

我们有“连接在一起”和“运行时”的名称:

  1. 脚本
  2. 动态的

因此,DI容器只不过是动态脚本语言的解释器。实际上,让我重新表述一下:一个典型的Java/.NET DI容器只不过是一个糟糕的动态脚本语言的糟糕的解释器,它的语法很难看,有时是基于XML的。

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

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

(这里有一个简单的例子:在汇编中,一个子程序调用是一个非常重要的事情——你必须保存你的局部变量和寄存器到内存中,把你的返回地址保存在某个地方,改变你调用的子程序的指令指针,安排它在完成后以某种方式跳回你的子程序中,把在被调用者能找到它们的地方争论,等等。IOW:在汇编语言中,“子例程调用”是一种设计模式,在出现像Fortran这样有内置子例程调用的语言之前,人们正在构建自己的“子例程框架”。您是否会说,子例程调用在Python中是“不常见的”,仅仅因为您不使用子例程框架?)

顺便说一句:举一个例子,看看DI的逻辑结论,看看Gilad BrachaNewspeak Programming Language和他关于这个主题的著作:

IoC和DI在成熟的Python代码中非常常见。由于duck类型,您不需要框架来实现DI。

最好的例子是如何使用settings.py设置Django应用程序:

# settings.py
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL + '/1',
    },
    'local': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'snowflake',
    }
}

Django Rest框架大量使用DI:

class FooView(APIView):
    # The "injected" dependencies:
    permission_classes = (IsAuthenticated, )
    throttle_classes = (ScopedRateThrottle, )
    parser_classes = (parsers.FormParser, parsers.JSONParser, parsers.MultiPartParser)
    renderer_classes = (renderers.JSONRenderer,)

    def get(self, request, *args, **kwargs):
        pass

    def post(self, request, *args, **kwargs):
        pass

让我提醒一下(source):

"Dependency Injection" is a 25-dollar term for a 5-cent concept. [...] Dependency injection means giving an object its instance variables. [...].

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

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

相关问题 更多 >

    热门问题