from dataclasses import dataclass from types import LambdaType, FunctionType from typing import Mapping, Type, TypeVar T = TypeVar("T") class ServiceLookupException(Exception): pass @dataclass class ServiceContainer: _singletons: Mapping[str, T] _factories: Mapping[str, T] def register(self, name: str, instance: T) -> None: if type(instance) is LambdaType or type(instance) is FunctionType: self._factories[name] = instance else: self._singletons[name] = instance def retrieve(self, name: str, _: Type[T]) -> T: if name in self._singletons: return self._singletons[name] elif name in self._factories: return self._factories[name]() raise ServiceLookupException(f"Could not locate service with name {name}") @dataclass class Foo: bar: str def __post_init__(self): print(f"Initialized with {self.bar}") container = ServiceContainer({}, {}) container.register("foo_lam", lambda : Foo("bar")) foo_single = Foo("baz") container.register("foo_single", foo_single) mc1 = container.retrieve("foo_lam", Type[Foo]) mc2 = container.retrieve("foo_lam", Type[Foo]) mc3 = container.retrieve("foo_single", Type[Foo]) mc4 = container.retrieve("foo_single", Type[Foo]) print(mc1.bar) print(mc2.bar) print(mc3.bar) print(mc4.bar)