
依赖注入是静态语言中的主流,但在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的内置patch功能已经提供了出色的测试能力,消除了依赖注入的主要好处之一。虽然依赖注入仍然可以帮助减少复杂性,但Python有其他方法来实现相同的目标。
我并不是说不应该在Python中使用依赖注入。恰恰相反,像所有工具和模式一样,有使用它们的地方和时机。依赖注入只是你工具箱中的另一个工具,它将提高你代码的质量。
我认为依赖注入通常会提高大多数Python项目的代码质量。
如果你有兴趣进一步探索依赖注入,我建议查看两个流行的Python框架:
- Injector (github.com/python-injector/injector)
- Dependency Injector (python-dependency-injector.ets-labs.org)
作者:Chuck Conway 专注于软件工程和生成式人工智能。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube。