This skill should be used when the user asks to "implement dependency injection in Python", "use the dependency-injector library", "decouple Python components", "write testable Python services", or needs guidance on Inversion of Control, DI containers, provider types, and wiring in Python applications.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
This skill should be used when the user asks to "implement dependency injection in Python", "use the dependency-injector library", "decouple Python components", "write testable Python services", or needs guidance on Inversion of Control, DI containers, provider types, and wiring in Python applications.
Python Dependency Injection
Dependency Injection (DI) is a design pattern where a class receives its dependencies from an external source rather than constructing them internally. This decouples components, improves testability, and enables flexible configuration without modifying production code.
Core Concept: Inversion of Control
Inversion of Control (IoC) shifts responsibility for creating and managing dependencies from the dependent class to an external orchestrator (a container or the caller). The class declares what it needs; something else provides it.
Wiring eliminates manual dependency passing in function calls. Decorate a function with @inject, mark parameters with Provide[...], then call container.wire():
from dependency_injector.wiring import inject, Provide
@injectdefmain(service: Service = Provide[Container.service]) -> None:
service.do_work()
if __name__ == "__main__":
container = Container()
container.config.from_env(...)
container.wire(modules=[__name__])
main() # service is injected automatically
Wire entire packages at once: container.wire(packages=["myapp"]).
Overriding for Tests
Override any provider without modifying application code:
# In testswith container.api_client.override(mock.Mock()):
main() # the mock is injected instead
Centralize dependency configuration — define all providers in one container module, not scattered across the codebase.
Avoid circular dependencies — if A depends on B and B depends on A, restructure or use a factory provider to delay instantiation.
Use the right scope — Singleton for stateless shared resources; Factory for stateful per-request objects. Mismatched scopes cause subtle state leakage bugs.
Lock dependency versions — pin exact versions in a lock file (poetry.lock, pip-compile output) to avoid dependency confusion attacks.
Anti-Patterns to Avoid
Anti-pattern
Problem
Fix
Service Locator
container.get(Service) inside business logic hides dependencies
Inject explicitly via constructor or @inject
Over-injection
10+ constructor params
Split into smaller, focused classes
Tight coupling
self.dep = ConcreteClass() inside __init__
Accept dependency as parameter
Scope mismanagement
Singleton wrapping a stateful request-scoped object
Use Factory or Resource with correct scope
Monkey-patching in tests
module.SomeClass = MockClass
Use container.override() or dependency_overrides
Quick Reference
pip install dependency-injector # base
pip install "dependency-injector[yaml]"# + YAML config support
pip install "dependency-injector[pydantic2]"# + Pydantic v2 settings
# Minimal working containerfrom dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
classContainer(containers.DeclarativeContainer):
config = providers.Configuration()
service = providers.Factory(MyService, setting=config.setting)
@injectdefhandler(svc: MyService = Provide[Container.service]):
svc.run()
container = Container()
container.config.from_dict({"setting": "value"})
container.wire(modules=[__name__])
handler()
Additional Resources
For detailed coverage of advanced topics, consult: