依赖注入是静态语言中的主要工具,但在Python中使用它是否有意义?它会让我成为更好的Python程序员吗?
等等,依赖注入又是什么?
首先,让我们回答这个问题:什么是依赖注入(DI)?
依赖注入是一种模式,使用时,它将对象的构造移到类外部。相反,该类依赖于一个抽象。
在C#和Java等静态语言中,依赖注入被广泛使用以减少耦合并促进测试。实际上,你会发现依赖注入框架的唯一目的是维护依赖关系及其相互之间的关系。
依赖注入有两个主要目的:
首先,它通过依赖抽象来降低复杂性。
其次,依赖抽象允许不同的实现(包括用于测试的模拟)被传递到类或函数中。
让我用一些代码来演示:
# Before
class User:
def __init__(self):
self.database = SqlServerDatabase()
def get_details(self, user_id: int):
self.database.get_user_details(user_id)
# After
class User:
def __init__(self, database: Database):
self.database = database
def get_details(self, user_id: int):
self.database.get_user_details(user_id)
这是最简单形式的依赖注入。虽然这个概念很直接,但它的强大之处在于能够实现灵活的设计。
在Before示例中,User类与SqlServerDatabase类紧密耦合。如果我们想测试User类,我们需要创建一个新的SqlServerDatabase实例。
在After示例中,User类与Database抽象松散耦合。我们可以将Database抽象的不同实现传递给User类。
让我用一个实际的例子来演示这种灵活性,展示我们如何在不同的数据库实现之间切换:
date_string = "2023-10-01" # Example date string
date_format = "%Y-%m-%d" # Input string format
birthday = datetime.strptime(date_string, date_format)
turn_of_the_century = datetime.strptime('2000-01-01', date_format)
database = PostgresDatabase("")
if birthday < turn_of_the_century:
database = SqlServerDatabase("")
user = User(database=database)
user.get_details(user_id=1)
在第6行(birthday < turn_of_the_century),依赖注入允许我们根据不同的条件轻松交换实现。虽然这种灵活性对生产代码很有价值,但依赖注入最常见的用途之一,特别是在静态语言中,是在测试中。
以下是一个例子:
class UserTests(unittest.TestCase):
def test_is_authenticated(self):
database = MockDatabase('connection_string')
is_authenticated = User(database).is_authenticated('user', 'pass')
self.assertTrue(is_authenticated)
这是一个使用MockDatabase类的简单例子。在Python中,我们也可以使用内置的Mock类来实现相同的结果。
有趣的是,在我参与过的Python项目中,依赖注入并未被广泛使用。来自静态语言背景,我感到惊讶——这似乎有悖常理。
然而,这种有限采用是有原因的。Python内置的补丁功能已经提供了出色的测试能力,消除了依赖注入的主要优势之一。虽然依赖注入仍然可以帮助降低复杂性,但Python有其他方法来实现相同的目标。
我并不是说不应该在Python中使用依赖注入。恰恰相反,像所有工具和模式一样,使用它们都有合适的时间和地点。依赖注入只是你工具箱中的另一个工具,它将提高你代码的质量。
我认为依赖注入通常会提高大多数Python项目的代码质量。
如果你有兴趣进一步探索依赖注入,我建议你查看两个流行的Python框架:
- Injector (github.com/python-injector/injector)
- Dependency Injector (python-dependency-injector.ets-labs.org)
作者:Chuck Conway 是一位 AI 工程师,拥有近 30 年的软件工程经验。他构建实用的 AI 系统——内容管道、基础设施代理和解决实际问题的工具——并分享他沿途的学习成果。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube 和 SubStack。