Dependency Cache
Often, you will have dependencies that share a sub dependency.
For example, you probably only want to load your configuration from environment variables once and then re-use the same object in multiple dependencies.
To avoid re-computing the shared dependency, di
will cache shared dependencies.
How caching works
Dependencies are cached by their cache key, computed in Dependent.cache_key
.
See dependents for more information on Dependent.cache_key
.
Dependencies are cached by default, but this behavior can be changed on a per-dependency basis using the use_cache=False
parameter to Dependent
.
from random import random
from di import Container
from di.dependent import Dependent, Marker
from di.executors import SyncExecutor
from di.typing import Annotated
def controller(
# no marker is equivalent to Dependent(object)
v1: object,
# the default value is use_cache=True
v2: Annotated[object, Marker(object, scope="request")],
# but you can set use_cache=False
v3: Annotated[float, Marker(random, use_cache=False, scope="request")],
) -> None:
assert v1 is v2
assert v1 is not v3 and v2 is not v3
def main() -> None:
container = Container()
solved = container.solve(Dependent(controller, scope="request"), scopes=["request"])
with container.enter_scope("request") as state:
solved.execute_sync(executor=SyncExecutor(), state=state)
Caching and scopes
Dependencies are cached within their scope and any inner scopes. Once a dependency's scope exits, it's cached value is discarded and the next time the scope is entered a fresh value will be computed.