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
, andSelector
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
, andjson
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