Python模块解耦的核心是通过接口约定、运行时注入或配置驱动控制依赖关系,避免硬编码;用Protocol/ABC抽象接口、依赖注入容器、配置驱动工厂及事件总线实现职责清晰、通信可控的松耦合。

Python模块解耦的核心是让各模块职责清晰、通信可控,不直接硬编码依赖,而是通过接口约定、运行时注入或配置驱动来降低耦合度。关键不在“删掉import”,而在“控制何时、如何、由谁来建立依赖关系”。
用抽象接口替代具体实现引用
避免模块A直接导入并实例化模块B的某个类;改为定义一个协议(Protocol)或抽象基类(ABC),让A只依赖接口,B负责实现。运行时再把B的实例传给A(如通过构造函数或setter)。
- 例如:日志模块不写red">from db import MySQLLogger,而是定义class Logger(ABC): def log(self, msg): ...,主业务模块只接收一个Logger实例
- Python 3.8+ 推荐用typing.Protocol做轻量契约,无需继承,更灵活
依赖注入(DI)代替手动初始化
把对象创建和组装逻辑从业务代码中抽离,交由专门的容器或工厂管理。模块之间不再互相new,而是声明“我需要什么”,由外部提供。
- 小项目可用简单函数工厂:def create_service(): return UserService(LoggerImpl(), CacheClient())
- 中大型项目可引入dependency-injector或DInjector等库,支持单例、作用域、自动解析
- Flask/FastAPI用户可直接利用其app.dependency_overrides做测试隔离
配置驱动行为,而非条件import
避免在代码里写if env == 'prod': from xxx import A else: from yyy import B。应统一读取配置(如pydantic-settings),再由工厂根据配置值决定实例化哪个类。
立即学习“Python免费学习笔记(深入)”;
- 配置项建议用字符串标识实现类型(如"redis_cache"、"file_logger"),避免暴露模块路径
- 配合entry_points或插件机制,还能支持运行时动态加载第三方实现
跨模块通信走事件或消息,不直调方法
当模块A需通知模块B某事发生(如“订单已支付”),别写b_module.handle_payment(order),改用事件总线或发布-订阅模式。
- 轻量场景可用blinker或pyee发事件,B模块提前注册监听器
- 强调解耦时,可引入消息队列(如Redis Pub/Sub、RabbitMQ),让A和B完全无代码依赖
- 注意事件数据要序列化友好,避免传入模块内部对象实例
不复杂但容易忽略:解耦不是追求绝对零依赖,而是让依赖变得显式、可测、可换。每次加一个import前,先问一句——这个依赖是我必须现在就要用的实现,还是可以推迟到运行时再决定?










