Skip to content

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 Dependant.cache_key. See dependants for more information on Dependant.cache_key. Dependencies are cached by default, but this behavior can be changed on a per-dependency basis using the use_cache=False parameter.

from random import random

from di import Container, Dependant, SyncExecutor
from di.typing import Annotated


def controller(
    # no marker is equivalent to Dependant(object)
    v1: object,
    # the default value is use_cache=True
    v2: Annotated[object, Dependant(object, scope="request")],
    # but you can set use_cache=False
    v3: Annotated[float, Dependant(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(scopes=["request"])
    solved = container.solve(Dependant(controller, scope="request"))
    with container.enter_scope("request"):
        container.execute_sync(solved, executor=SyncExecutor())

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.