使用Python注入器模块复制指南@Named

问题描述 投票:0回答:2

我正在使用 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 结合管理)。

是否有另一种方法可以完成此任务,但不能解析子类?

python dependency-injection guice
2个回答
1
投票

可以使用来自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  

0
投票

如果您使用flask_injector,我认为使用NewType而不是Annotated更合适,因为如果您有多个字符串要注入,则始终会返回第一个定义的值

© www.soinside.com 2019 - 2024. All rights reserved.