我正在使用 injector 模块,它体现了 DI 框架的大部分 Guice API。
我试图完成 Guice 使用 @Named 绑定注释所做的事情。也就是说,使用
injector.Module
重写 configure
方法并使用 Binder 绑定多个相同类型但名称不同的实例:
import pathlib
import injector
ConfigFile = pathlib.WindowsPath
UserFile = pathlib.WindowsPath
cfg_file = pathlib.Path.home() / 'settings.cfg'
usr_file = pathlib.Path.home() / 'user.inf'
class AppModule(injector.Module):
def configure(self, binder):
binder.bind(ConfigFile, to=cfg_file) # Guice uses annotatedWith here
binder.bind(UserFile, to=usr_file) # Guice uses annotatedWith here
class App:
@injector.inject
def __init__(self, cfg: ConfigFile, usr: UserFile):
self.config = cfg
self.user = usr
app = injector.Injector(AppModule).get(App)
print(app.config, app.user) # prints the contents of `usr_file` for both
我认为 Binder.multibind 我有一定的可行性,但我的尝试没有成功。我能设计的唯一解决方案是
pathlib.Path
必须被子类化,并且这些子类显式绑定到它们的实例(可以在 injector.Module
中使用 @provider 与 @singleton 结合管理)。
是否有另一种方法可以完成此任务,但不能解析子类?
可以使用来自typing_extensions(已经是注入器的依赖项或来自Python 3.9打字)的注释。在上面的示例中只需替换
ConfigFile = pathlib.WindowsPath
UserFile = pathlib.WindowsPath
与
ConfigFile = Annotated[pathlib.WindowsPath, 'config']
UserFile = Annotated[pathlib.WindowsPath, 'user']
它应该有效。
使用 Typing.NewType 是可行的,但它可能无法与静态类型检查器很好地配合。
这是在 python 3.6 上测试的完整工作示例:
from injector import Injector, inject, Module, singleton, provider
from typing_extensions import Annotated
from typing import NewType, Callable
# You can use Greeting instead of Annotated[str, 'greeting'] as it's the same type
Greeting = Annotated[str, 'greeting']
class Greeter:
@inject
def __init__(self, greeting: Annotated[str, 'greeting']):
self.greeting = greeting
def greet(self):
print(self.greeting)
class MyModule(Module):
def configure(self, binder):
binder.bind(Greeting, to='Howdy', scope=singleton)
binder.bind(str, to='Hello', scope=singleton)
def main():
injector = Injector([MyModule()])
greeter = injector.get(Greeter)
greeter.greet()
if __name__ == '__main__':
main()
有一点问题,如果您不提供
Annotated[str, 'greeting']
的绑定,注入器将使用默认构造函数来生成一些内容,但可能不是您所期望的。另一方面,它以同样的方式处理 str - 愉快地构造一个空字符串。
在安装了以下软件包的conda环境中进行测试(使用pip安装注入器):
# Name Version
injector 0.18.4
libffi 3.0.9
pip 18.1
python 3.6.8
setuptools 40.8.0
sqlite 3.26.0
typing-extensions 3.7.4.3
wheel 0.33.1
xz 5.2.3
如果您使用flask_injector,我认为使用NewType而不是Annotated更合适,因为如果您有多个字符串要注入,则始终会返回第一个定义的值