一文带你深入了解Python依赖注入。
微信搜索关注《Python学研大本营》,加入读者群,分享更多精彩
简介
依赖注入是软件工程中使用的一种设计模式,它允许在创建对象时由外部提供其依赖关系,而不是自己创建这些依赖关系。换句话说,不是从类创建自己的依赖关系,而是将依赖关系从外部注入到该类。
为什么使用依赖注入?
依赖注入的好处包括提高软件设计的灵活性和模块化,改善可测试性,以及减少组件之间的耦合。通过将对象与它们的依赖关系解耦,可以更容易地进行更改而不影响系统的其他部分。
例如,假设有一个依赖于数据库连接的类。如果在该类中创建数据库连接,就在该类和数据库之间建立了一个紧密的耦合。这意味着对数据库连接的任何更改都需要对类进行修改,这使得代码的灵活性降低,更难维护。
通过依赖注入,可以从外部将数据库连接传递给类,使代码更加模块化,更容易测试。这也允许用不同的实现来替换数据库连接,比如与不同的数据库或外部API进行交互,而不需要修改类本身。
用Python实现依赖注入
Python是一种流行的编程语言,支持几种实现依赖注入的方法。本文将使用构造函数注入来演示这一概念。
构造函数注入包括通过构造函数将依赖关系传递给一个类。这允许该类将依赖关系存储为实例变量,使它们对其方法可用。
创建一个例子来演示它是如何工作的。将从定义一个依赖于UserRepository
接口的UserService
类开始:
class UserService:def __init__(self, user_repository):self.user_repository = user_repositorydef get_user(self, user_id):return self.user_repository.get_user(user_id)
在此示例中,UserService
类在其构造函数中把UserRepository
对象作为一个参数。然后它将UserRepository
对象存储为一个实例变量,并在其get_user
方法中使用它。
可以通过给UserRepository
添加一个get_user
方法来定义它的接口:
class UserRepository:def get_user(self, user_id):raise NotImplementedError
这创建了一个简单的接口,UserRepository
类的任何实现都必须实现。在这种情况下将创建一个UserRepository
类的实现,叫做InMemoryUserRepository
,它将用户数据存储在内存中:
class InMemoryUserRepository(UserRepository):def __init__(self):self.users = {1: {"id": 1, "name": "Alice"},2: {"id": 2, "name": "Bob"},3: {"id": 3, "name": "Charlie"},}def get_user(self, user_id):return self.users.get(user_id, None)
在InMemoryUserRepository
类中,定义了一个包含用户数据的字典,并实现了get_user
方法,通过ID检索用户。
最后,在主函数中,创建了一个InMemoryUserRepository
的实例,并将其传递给UserService
的构造函数。然后在UserService
实例上调用get_user
方法,通过他们的ID检索用户:
if __name__ == "__main__":user_repository = InMemoryUserRepository()user_service = UserService(user_repository)user = user_service.get_user(1)
在此示例中,创建一个InMemoryUserRepository
的实例,它实现了UserRepository
接口。然后创建一个UserService
的实例,将InMemoryUserRepository
实例作为参数传给它的构造函数。最后,在UserService
实例上调用get_user
方法,通过ID检索一个用户。
通过使用构造函数注入,可以很容易地将UserRepository
的实现换成不同的实现,比如与数据库或外部API交互的实现,而不需要修改UserService
类本身。这使得代码更灵活,更容易维护。
如下所示是完整的InMemoryUserRepository.py
文件:
from UserRepository import UserRepository
from UserService import UserServiceclass InMemoryUserRepository(UserRepository):def __init__(self):self.users = {1: {"id": 1, "name": "Alice"},2: {"id": 2, "name": "Bob"},3: {"id": 3, "name": "Charlie"},}def get_user(self, user_id):return self.users.get(user_id, None)if __name__ == "__main__":user_repository = InMemoryUserRepository()user_service = UserService(user_repository)user = user_service.get_user(1)print(user.get("name"))
接下来的例子展示了如何用DatabaseUserRepository
的实现来替换InMemoryUserRepository
的实现:
import os
import sqlite3
from UserRepository import UserRepository
from UserService import UserServiceclass DatabaseUserRepository(UserRepository):def __init__(self, db_path):self.db_path = db_pathdef get_user(self, user_id):with sqlite3.connect(self.db_path) as conn:cursor = conn.cursor()cursor.execute("SELECT id, name FROM users WHERE id=?", (user_id,))row = cursor.fetchone()if row is None:return Nonereturn {"id": row[0], "name": row[1]}if __name__ == "__main__":# 用`DatabaseUserRepository`来替换`InMemoryUserRepository`db_dir = "test"os.makedirs(db_dir, exist_ok=True)db_path = os.path.join(db_dir, "test.db")with sqlite3.connect(db_path) as conn:cursor = conn.cursor()cursor.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")cursor.execute('INSERT INTO users (id, name) VALUES (1, "Alice")')cursor.execute('INSERT INTO users (id, name) VALUES (2, "Bob")')cursor.execute('INSERT INTO users (id, name) VALUES (3, "Charlie")')user_repository = DatabaseUserRepository(db_path)user_service = UserService(user_repository)user = user_service.get_user(1)print(user["name"])
在此示例中,os
模块被用来在当前工作目录中创建一个名为“test
”的新目录(如果它还不存在的话),并且通过连接目录路径和文件名“test.db
”来创建SQLite
数据库文件的路径。
然后建立与数据库的连接,创建一个用户表,并将一些测试数据插入该表中。
最后,创建一个DatabaseUserRepository
类的实例,db_path
参数设置为测试数据库文件的路径,这个实例被用来创建UserService
类的实例。然后调用UserService
类的get_user()
方法,参数为1
,ID为1
的用户的名字被打印到控制台。
本文的所有代码都可以在Github上找到:https://github.com/PythonCodeNemesis/Python_Dependancy_Injector_Demo
总结
依赖注入是一种强大的设计模式,可以帮助使软件更加模块化、更加灵活、更加容易测试。Python提供了几种实现依赖注入的方法,包括构造函数注入,在本文中演示了这种方法。
通过使用依赖注入,可以创建与依赖关系解耦的类,使修改和维护代码更加容易。这也可以提高软件的整体质量,并使其更有弹性地应对长期的变化。
推荐书单
《Python从入门到精通(微课精编版)》
《Python从入门到精通(微课精编版)》使用通俗易懂的语言、丰富的案例,详细介绍了Python语言的编程知识和应用技巧。全书共24章,内容包括Python开发环境、变量和数据类型、表达式、程序结构、序列、字典和集合、字符串、正则表达式、函数、类、模块、异常处理和程序调试、进程和线程、文件操作、数据库操作、图形界面编程、网络编程、Web编程、网络爬虫、数据处理等,还详细介绍了多个综合实战项目。其中,第24章为扩展项目在线开发,是一章纯线上内容。全书结构完整,知识点与示例相结合,并配有案例实战,可操作性强,示例源代码大都给出详细注释,读者可轻松学习,快速上手。本书采用O2O教学模式,线下与线上协同,以纸质内容为基础,同时拓展更多超值的线上内容,读者使用手机微信扫一扫即可快速阅读,拓展知识,开阔视野,获取超额实战体验。
《Python从入门到精通(微课精编版)(软件开发视频大讲堂)》(前沿科技)【摘要 书评 试读】- 京东图书京东JD.COM图书频道为您提供《Python从入门到精通(微课精编版)(软件开发视频大讲堂)》在线选购,本书作者:,出版社:清华大学出版社。买图书,到京东。网购图书,享受最低优惠折扣!https://item.jd.com/13524355.html
精彩回顾
《用好这9个技巧,让你的Python代码“飞”起来》
《领略数学之美,使用Python创建分形图案》
《使用Python进行自动化录屏》
《轻松完成异步任务,一文搞懂Python Celery》
《ChatGPT插件使用攻略,解锁互联网新体验》
《使用Python轻松创建Flask API后台任务》
《使用ChatGPT API创建Python文档,竟然如此简单》
微信搜索关注《Python学研大本营》,加入读者群
访问【IT今日热榜】,发现每日技术热点