跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonSaaSPay

Python 依赖注入(DI)三种实现方式与可测试性实践

Python 依赖注入通过分离对象创建与使用降低耦合。主要实现方式包括显式传参、工厂函数及容器框架。显式传参可读性强但参数多;工厂函数集中管理配置;容器框架适合大型系统但有学习成本。以电商支付场景为例,通过重构全局单例为显式注入,结合 FastAPI Depends 与单元测试 Mock,可显著提升代码覆盖率至 98% 以上并支持并行测试。推荐根据项目规模选择合适模式,优先保证依赖关系透明化。

橘子海发布于 2026/3/25更新于 2026/10/24101 浏览
Python 依赖注入(DI)三种实现方式与可测试性实践

Python 依赖注入(DI)三种实现方式与可测试性实践

概述

依赖注入(Dependency Injection,简称 DI)是解决大型项目中依赖关系混乱、代码难以测试和维护的关键模式。它将对象的创建与使用分离,使代码更松耦合、更易扩展。结合类型提示(typing + mypy)和现代框架,Python 能优雅承载所有 DI 模式。

基础概念

依赖注入的实现离不开 Python 核心语法与面向对象机制。

  • 核心语法与数据类型:列表、字典、集合、元组是构建依赖容器的基础;条件语句、循环和异常处理确保注入逻辑健壮。
config = {"db_url": "sqlite:///test.db", "timeout": 30}
items = [1, 2, 3]
  • 函数与面向对象编程:函数定义、参数传递、匿名函数(lambda)和装饰器是 DI 的基础工具。类通过构造方法接收依赖,实现封装与多态。
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 花费时间:{end - start:.4f}秒")
        return result
    return wrapper

@timer
def compute_sum(n):
    return sum(range(n))

print(compute_sum(1000000))

主流实现方式

Python 提供三种主流 DI 方式,每种都对应不同复杂度场景。

1. 显式传参(Constructor Injection / Function Injection)

最简单、最推荐的纯 Python 方式:直接在构造方法或函数参数中传入依赖。

class PaymentService:
    def __init__(self, db: Database, email_sender: EmailSender):
        self.db = db
        self.email_sender = email_sender

    def process_payment(self, order_id: int, amount: float):
        self.db.save_transaction(order_id, amount)
        self.email_sender.send_confirmation(order_id)

2. 工厂函数(Factory Pattern)

工厂函数负责组装依赖,适合配置驱动场景。

def create_payment_service() -> PaymentService:
    db = Database(config["db_url"])
    email = SmtpEmailSender(config["smtp_host"])
    return PaymentService(db, email)

3. 容器框架(Dependency Injector / FastAPI Depends)

使用第三方容器自动解析依赖,适合大型项目。

from dependency_injector import containers, providers

class Container(containers.DeclarativeContainer):
    db = providers.Singleton(Database, url=config["db_url"])
    email_sender = providers.Singleton(SmtpEmailSender, host=config["smtp_host"])
    payment_service = providers.Factory(PaymentService, db=db, email_sender=email_sender)

container = Container()
service = container.payment_service()

代价权衡

三种方式各有权衡,选择取决于项目规模。

  • 显式传参:优势为零魔术、高可读、易静态检查;代价为上层代码需层层传递依赖。适用于单元测试友好场景。
  • 工厂函数:优势为集中管理创建逻辑,便于切换实现;代价为引入一层间接性,调试时需追踪工厂调用链。适用于配置动态加载场景。
  • 容器框架:优势为自动解析、支持作用域、配置外部化;代价为学习曲线陡峭、运行时魔术、可能隐藏依赖关系。适用于微服务或大型系统。

总体代价排序(由低到高):显式传参 < 工厂函数 < 容器框架。

实战案例:提升可测试性

以电商'订单支付'模块为例,传统写法常把依赖藏进全局单例,导致测试时无法 mock、产生副作用。

错误示范(全局单例)

# bad.py
global_db = Database()

class PaymentService:
    def process(self, order_id):
        global_db.save(...)

正确重构(显式传参 + 工厂 + 测试友好)

  1. 领域层(纯净、无全局)
class PaymentService:
    def __init__(self, db: Database, notifier: Notifier):
        self.db = db
        self.notifier = notifier

    def process_payment(self, order_id: int, amount: float):
        transaction = Transaction(order_id, amount)
        self.db.save(transaction)
        self.notifier.send("支付成功", order_id)
  1. 工厂 + 上下文管理(生产环境)
from contextlib import contextmanager

@contextmanager
def get_payment_service():
    db = Database(get_db_url())
    notifier = EmailNotifier()
    service = PaymentService(db, notifier)
    try:
        yield service
    finally:
        db.close()
  1. FastAPI 应用层集成(异步 DI)
from fastapi import Depends, FastAPI

def get_db():
    db = Database()
    try:
        yield db
    finally:
        db.close()

app = FastAPI()

@app.post("/pay")
def pay(order_id: int, service: PaymentService = Depends(lambda: PaymentService(get_db(), EmailNotifier()))):
    service.process_payment(order_id, 99.9)

单元测试案例(pytest + mocks)

def test_payment_success():
    mock_db = Mock()
    mock_notifier = Mock()
    service = PaymentService(mock_db, mock_notifier)
    service.process_payment(123, 99.9)
    mock_db.save.assert_called_once()
    mock_notifier.send.assert_called_once_with("支付成功", 123)

总结

依赖注入在 Python 中高度实用:显式传参提供透明基础,工厂函数实现灵活组装,容器框架支撑大规模自动化。通过电商支付案例,可以看到它如何彻底解决全局单例问题,让代码真正可测、可维护。建议根据项目规模选择合适模式,优先保证依赖关系透明化。

目录

  1. Python 依赖注入(DI)三种实现方式与可测试性实践
  2. 概述
  3. 基础概念
  4. 主流实现方式
  5. 1. 显式传参(Constructor Injection / Function Injection)
  6. 2. 工厂函数(Factory Pattern)
  7. 3. 容器框架(Dependency Injector / FastAPI Depends)
  8. 代价权衡
  9. 实战案例:提升可测试性
  10. 错误示范(全局单例)
  11. bad.py
  12. 正确重构(显式传参 + 工厂 + 测试友好)
  13. 单元测试案例(pytest + mocks)
  14. 总结

更多推荐文章

查看全部
  • Linux 读写锁深度解析:原理、应用与性能优化
  • Coze 基于行业文章生成思维导图工作流详解
  • Python 与前端集成构建全栈应用指南
  • MVP 至高并发:AI 在前后端开发中的差异化落地实践
  • Windows 环境下 Java 多版本管理与切换指南
  • Python SQLAlchemy ORM 数据库操作指南
  • Stable Diffusion v2-1-base 模型使用指南与代码实践
  • GitHub Copilot Agent 模式实战指南与避坑经验
  • 金仓数据库 SQL 防火墙:白名单驱动的安全防护
  • Python 爬虫入门与数据分析基础指南
  • 高性能计算 FPGA 开发:Quartus Prime 18.0 安装配置指南
  • Openclaw 开源仿生机械爪原理与应用解析
  • Hunyuan-MT-7B-WEBUI 图形化界面详解
  • ES6 新特性实战:进制表示、Symbol 与类继承
  • Stable Diffusion ControlNet 基础使用指南
  • Qwen3 与 Qwen Agent 智能体开发实战:接入 MCP 工具
  • Hunyuan-MT-7B 助力国际 NGO 在华项目多语本地化
  • 基于 YOLO 与 LLM 的 Web 目标检测与智能分析系统
  • 命令行下的 MCP 桥接工具:MCPHost 实践与模型兼容性测试
  • Mac mini 部署 OpenClaw:接入国产大模型与飞书机器人

相关免费在线工具

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online