在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中的工作方式。你可以免费获得一种“单例”,只需从模块中导入它。在模块中定义一个对象的实际实例,然后任何客户端代码都可以导入它,并实际获得一个工作的、完全构造/填充的对象。

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

其他回答

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

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

Class B:
    pass

Class C:
    pass

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

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.

看看FastAPI,它内置了依赖注入。例如:

from fastapi import Depends, FastAPI

async def get_db():
    db = DBSession()
    try:
        yield db
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()

app = FastAPI()

@app.get("/items")
def get_items(db=Depends(get_db)):
    return db.get_items()

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

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

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

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

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

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.