Stay Hungry,Stay Foolish!

DI - Dependency Injection

DI

https://www.professionalqa.com/dependency-injection

What is Dependency Injection?

A software design pattern that implements inversion of control for resolving dependencies is known as Dependency Injection. In dependency injection a ‘dependency’ is an object that can be used (service) and ‘injection’ is the passing of a dependency to a dependent object or a client that would use it. Dependency Injection is a subset of Inversion of Control (IOC) that supports the dependency inversion principle and is a way of injecting properties to an object. Additionally, it explains how to inject the concrete implementation into an object that is using abstraction. The main idea of Dependency Injection is to reduce the coupling between objects and to move the binding of abstraction and concrete implementation out of the dependent object. Dependency injection is how one object gets information about the other dependent object, which is abstracted. Moreover, dependency injection provides objects what they require and ensure that this process is hassle free.

 

WHY?

http://www.jeremybytes.com/Downloads/DependencyInjection.pdf

 

 

 

 

injector -- Python dependency injection framework, inspired by Guice

https://github.com/alecthomas/injector

While dependency injection is easy to do in Python due to its support for keyword arguments, the ease with which objects can be mocked and its dynamic nature, a framework for assisting in this process can remove a lot of boiler-plate from larger applications. That's where Injector can help. It automatically and transitively provides dependencies for you. As an added benefit, Injector encourages nicely compartmentalised code through the use of :ref:modules <module>.

If you're not sure what dependency injection is or you'd like to learn more about it see:

>>> from injector import Injector, inject
>>> class Inner:
...     def __init__(self):
...         self.forty_two = 42
...
>>> class Outer:
...     @inject
...     def __init__(self, inner: Inner):
...         self.inner = inner
...
>>> injector = Injector()
>>> outer = injector.get(Outer)
>>> outer.inner.forty_two
42

dependency-injector

https://python-dependency-injector.ets-labs.org/index.html

 

 

Dependency Injector is a dependency injection framework for Python.

It helps implementing the dependency injection principle.

Key features of the Dependency Injector:

  • Providers. Provides Factory, Singleton, Callable, Coroutine, Object, List, Dict, Configuration, Resource, Dependency, and Selector providers that help assemble your objects. See Providers.

  • Overriding. Can override any provider by another provider on the fly. This helps in testing and configuring dev/stage environment to replace API clients with stubs etc. See Provider overriding.

  • Configuration. Reads configuration from yaml, ini, and json files, pydantic settings, environment variables, and dictionaries. See Configuration provider.

  • Resources. Helps with initialization and configuring of logging, event loop, thread or process pool, etc. Can be used for per-function execution scope in tandem with wiring. See Resource provider.

  • Containers. Provides declarative and dynamic containers. See Containers.

  • Wiring. Injects dependencies into functions and methods. Helps integrate with other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See Wiring.

  • Asynchronous. Supports asynchronous injections. See Asynchronous injections.

  • Typing. Provides typing stubs, mypy-friendly. See Typing and mypy.

  • Performance. Fast. Written in Cython.

  • Maturity. Mature and production-ready. Well-tested, documented, and supported.

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject


class Container(containers.DeclarativeContainer):

    config = providers.Configuration()

    api_client = providers.Singleton(
        ApiClient,
        api_key=config.api_key,
        timeout=config.timeout,
    )

    service = providers.Factory(
        Service,
        api_client=api_client,
    )


@inject
def main(service: Service = Provide[Container.service]) -> None:
    ...


if __name__ == "__main__":
    container = Container()
    container.config.api_key.from_env("API_KEY", required=True)
    container.config.timeout.from_env("TIMEOUT", as_=int, default=5)
    container.wire(modules=[__name__])

    main()  # <-- dependency is injected automatically

    with container.api_client.override(mock.Mock()):
        main()  # <-- overridden dependency is injected automatically

 

类方法注入

from unittest import mock

from dependency_injector import containers, providers
from dependency_injector.wiring import Provide, inject

from after import ApiClient, Service


class Container(containers.DeclarativeContainer):

    config = providers.Configuration()

    api_client = providers.Singleton(
        ApiClient,
        api_key=config.api_key,
        timeout=config.timeout,
    )

    service = providers.Factory(
        Service,
        api_client=api_client,
    )


@inject
def main(service: Service = Provide[Container.service]) -> None:
    print("sss")


class TEST:
    @inject
    def __init__(self, service: Service = Provide[Container.service]):
        # service.hello()
        self._service = service
        # print("test")

    @inject
    def run(self, service: Service = Provide[Container.service]):
        service.hello()



if __name__ == "__main__":
    container = Container()
    # container.config.api_key.from_env("API_KEY", required=True)
    # container.config.timeout.from_env("TIMEOUT", as_=int, default=5)
    container.wire(modules=[__name__])

    test: TEST = TEST()
    test.run()

    main()  # <-- dependency is injected automatically

    with container.api_client.override(mock.Mock()):
        main()  # <-- overridden dependency is injected automatically

service所在的after文件

import os


class ApiClient:

    def __init__(self, api_key: str, timeout: int) -> None:
        self.api_key = api_key  # <-- dependency is injected
        self.timeout = timeout  # <-- dependency is injected


class Service:

    def __init__(self, api_client: ApiClient) -> None:
        self.api_client = api_client  # <-- dependency is injected

    def hello(self):
        print("hello")


def main(service: Service) -> None:  # <-- dependency is injected
    ...


if __name__ == "__main__":
    main(
        service=Service(
            api_client=ApiClient(
                api_key=os.getenv("API_KEY"),
                timeout=int(os.getenv("TIMEOUT")),
            ),
        ),
    )

 github例: https://github.com/fanqingsong/fastapi-ml-skeleton/blob/master/fastapi_modules/ioc_framework/implement.py

 

posted @ 2022-09-28 23:53  lightsong  阅读(131)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel