Python后端Route-Controller-Feature-Repository架构依赖注入最佳实践咨询
寻找Pythonic的依赖注入实现方案(基于Route-Controller-Feature-Repository架构)
我正在对比TypeScript与Python的后端开发结构,采用Route - Controller - Feature - Repository架构(按需使用非基础方法)。该架构在TypeScript中广泛应用:路由调用控制器,控制器完成合法性校验后调用Feature,Feature按需对数据库执行操作。
TypeScript中通过index.ts初始化类并注入依赖,示例如下:
import SomeRepository from '...' class SomeFeature { private someRepository: SomeRepository; constructor(someRepository: SomeRepository) { this.someRepository = someRepository; } // ... 其他方法 }
import SomeRepository from '...' import SomeFeature from '...' export default new SomeFeature(new SomeRepository());
我在Python项目中找到了四种实现方式,但不确定哪种最符合Python风格,或存在Python特性冲突需规避:
OPTION 1:全局实例初始化
from ... import SomeRepository from ... import SomeFeature from ... import SomeController some_repository = SomeRepository() some_feature = SomeFeature(some_repository) some_controller = SomeController(some_feature) @app.get("/") async def some_endpoint(): return some_controller.main_function()
OPTION 2:工厂函数创建实例
from ... import SomeRepository from ... import SomeFeature def create_delete_document_feature(): some_repository = SomeRepository() return SomeFeature(some_repository)
OPTION 3:类内部直接初始化依赖
from ... import SomeRepository class SomeFeature: def __init__(self): self.some_repository = SomeRepository()
OPTION 4:FastAPI Depends 注入
from fastapi import Depends from ... import SomeRepository from ... import SomeFeature from ... import SomeController def get_some_repository(): return SomeRepository() def get_some_feature(some_repository=Depends(get_some_repository)): return SomeFeature(some_repository) def get_some_controller(some_feature=Depends(get_some_feature)): return SomeController(some_feature)
但选项4会为每个请求创建新实例,若Feature涉及模型加载会导致延迟,虽可尝试use_cache=True,但不确定是否为最优解,或应在应用启动时手动初始化实例并复用。
请问哪种方案是最佳选择?
各方案优劣分析与最佳选择
优先排除的选项
- OPTION 3:直接在
SomeFeature的__init__里实例化SomeRepository,完全违背依赖注入的核心逻辑——依赖倒置与解耦。后续若要替换SomeRepository实现(比如测试用Mock),必须修改SomeFeature源码,维护成本极高,绝对不推荐。 - OPTION 2:工厂函数比OPTION3更灵活,但本质还是硬编码创建依赖。如果后续需要调整依赖的初始化逻辑(比如给
SomeRepository传配置参数),所有调用工厂函数的地方都要修改,仅适合小型临时项目,不适合长期维护的架构。
核心对比:OPTION1 vs OPTION4
OPTION1:全局实例
- 优势:应用启动时一次性初始化所有实例,全程复用,彻底避免OPTION4的重复创建问题(比如模型仅加载一次)。结构简单直观,和你熟悉的TS写法逻辑一致,符合Python“显式优于隐式”的设计哲学。
- 注意点:仅需确保
SomeRepository、SomeFeature、SomeController是无状态的——这是该架构的常规设计(Repository只做数据库操作,Feature仅处理业务逻辑,不存储请求上下文),因此不会出现请求间状态污染的问题。
OPTION4:FastAPI Depends
- 优势:原生支持请求级别的依赖隔离,适合需要请求专属资源的场景(比如每个请求用独立的数据库会话)。
- 劣势:默认每个请求都会创建新实例,若Feature涉及模型加载等重初始化操作,会严重拖慢性能。虽然
use_cache=True能让同一个请求内复用实例,但跨请求仍会重复创建;如果手动在依赖函数里实现单例缓存,又会失去Depends的请求隔离优势,反而不如OPTION1直接高效。
最终建议
如果你的架构中,Repository、Feature、Controller均为无状态设计(这是该架构的标准实践),OPTION1是最符合Python风格的选择——它简单、显式,完全契合Python“简单胜于复杂”的原则,同时和你熟悉的TS实现逻辑对齐。
若后续遇到需要请求级隔离的场景(比如数据库会话管理),可以单独针对这类依赖用Depends处理,无需将所有层都改为请求级注入。例如:保留全局的Feature实例,但Feature的方法接收由Depends注入的数据库会话参数。
内容的提问来源于stack exchange,提问作者Alex Abades Grimes
相关产品推荐
相关产品推荐

