在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只需要一两行普通代码就可以完成。这就是函数式编程与命令式编程的优势所在。
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美元术语。[…依赖注入意味着给一个对象它的实例变量。[…]。
我支持“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