多迈知识库
第二套高阶模板 · 更大气的阅读体验

Python中的依赖注入实现与应用

发布时间:2025-12-14 14:50:22 阅读:275 次

什么是依赖注入

开发中经常遇到一个对象需要另一个对象来完成工作的情况。比如,一个订单服务需要数据库连接才能保存数据。如果每次都在类内部直接创建数据库连接,那这个类就和具体的数据库实现绑死了。

依赖注入就是把“需要的东西”从外面传进去,而不是在类里面自己 new 一个。这样代码更灵活,测试也更容易。

手动实现依赖注入

Python 没有强制的类型系统,实现依赖注入可以很轻量。比如写一个简单的邮件服务:

class EmailService:
def send(self, to: str, message: str):
print(f"发送邮件给 {to}:{message}")

class NotificationService:
def __init__(self, email_service):
self.email_service = email_service

def notify(self, user):
self.email_service.send(user, '您的订单已创建')

# 使用时从外部传入依赖
email_svc = EmailService()
notifier = NotificationService(email_svc)
notifier.notify('alice@example.com')

这里 NotificationService 不关心 email_service 到底是哪种实现,只要它有 send 方法就行。测试的时候完全可以传一个模拟对象。

用字典做简单的容器

项目大了以后,手动传参太麻烦。可以用一个字典管理所有服务实例,相当于一个简易的 IoC 容器:

class Container:
def __init__(self):
self._registry = {}

def register(self, key, instance):
self._registry[key] = instance

def get(self, key):
return self._registry[key]

# 注册服务
container = Container()
container.register('email_service', EmailService())
container.register('notifier', NotificationService(container.get('email_service')))

# 使用
notifier = container.get('notifier')
notifier.notify('bob@example.com')

使用第三方库:Dependency Injector

真实项目中推荐用成熟的库,比如 Dependency Injector。它支持工厂、单例、配置注入等模式。

先安装:pip install dependency-injector

from dependency_injector import containers, providers
from dependency_injector.injectors import inject

class Container(containers.DeclarativeContainer):
email_service = providers.Factory(EmailService)
notifier = providers.Factory(
NotificationService,
email_service=email_service
)

container = Container()

@inject
def create_order(notifier=container.notifier):
notifier().notify('charlie@example.com')

create_order()

这种方式让依赖关系集中管理,换实现时改一行代码就行。比如换成短信通知,只要替换注册部分,业务逻辑不用动。

配置注入也很实用

很多服务依赖配置项,比如数据库地址、API 密钥。Dependency Injector 也支持从环境变量或文件加载配置:

class ConfigContainer(containers.DeclarativeContainer):
config = providers.Configuration()

db_url = config.db.url.as_string()
debug = config.debug.as_bool()

然后在启动时加载配置:

container = ConfigContainer()
container.config.from_dict({
'db': {'url': 'sqlite:///local.db'},
'debug': True
})

这样一来,开发、测试、生产环境切换变得非常清晰。