在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进行依赖注入,但手动方法有其缺点:

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

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

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

其他回答

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

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

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

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

IoC容器主要使用**kwarg来“模仿”

class A:
    def __init__(self, **kwargs):
        print(kwargs)

Class B:
    pass

Class C:
    pass

Ainstance = A(b=B, c=C)

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

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

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

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

最好的例子是如何使用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 Framework充分利用了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

让我提醒一下(来源):

“依赖注入”是一个5美分概念的25美元术语。[…依赖注入意味着给一个对象它的实例变量。[…]。