This repository provides practical examples demonstrating how to implement Dependency Injection (DI) in Python applications, progressing from basic concepts to framework-based solutions.
Note: This project was developed with assistance from Claude Code. The original concepts and documentation focus came from a human developer, while Claude Code helped improve documentation consistency, add Protocol interfaces, and create comprehensive test examples. We believe in transparency about AI-assisted development.
Dependency Injection is a design pattern that decouples components from their dependencies. Instead of components creating their own dependencies internally, they receive them from the outside (injection).
class Service:
def __init__(self):
self.client = APIClient() # Tightly coupled!Problems:
- Cannot test without real APIClient
- Cannot swap implementations
- Hidden dependencies
class Service:
def __init__(self, client: APIClientProtocol): # Injected!
self.client = clientBenefits:
- Testability: Inject mocks for testing
- Flexibility: Swap implementations easily
- Clarity: Dependencies are explicit
| Benefit | Description |
|---|---|
| Testability | Inject mocks instead of real dependencies |
| Maintainability | Reduced coupling between components |
| Flexibility | Easy to swap implementations |
| Reusability | Components work in different contexts |
This project uses a combination of documentation approaches for maximum clarity:
| Approach | Purpose | Example |
|---|---|---|
| Type Hints | IDE autocompletion, static analysis | def get_user(id: int) -> User |
| Google Docstrings | Human-readable documentation | Args, Returns, Example sections |
| Protocols (PEP 544) | Interface definitions without inheritance | class APIClientProtocol(Protocol) |
- Python 3.8 or higher (Protocol support)
- pip (Python package manager)
- Clone the repository:
git clone <repository-url>
cd python_di_examples- Create and activate virtual environment:
python3 -m venv venv
source venv/bin/activate # Linux/Mac
# or
venv\Scripts\activate # Windows- Install dependencies:
# Production only
pip install -r requirements.txt
# Development (includes pytest)
pip install -r requirements-dev.txtCopy the example file and configure:
cp .env.example .envRequired variables:
API_KEY=your-api-key-here
TIMEOUT=30Or export directly:
export API_KEY="your-api-key"
export TIMEOUT=30Example 01 - Fundamentals
Demonstrates the journey from tightly coupled code to properly decoupled code.
| File | Description |
|---|---|
main_before.py |
Anti-pattern: tightly coupled dependencies |
main_di.py |
Solution: manual dependency injection |
Run:
python example_01/main_before.py # See the problem
python example_01/main_di.py # See the solutionKey learning: Understand WHY DI matters before using frameworks.
Example 02 - Framework DI
Introduces the dependency-injector framework to solve manual assembly limitations.
Features demonstrated:
- Container pattern for dependency management
- Providers: Singleton vs Factory
- Configuration from environment variables
- Automatic injection with
@injectdecorator - Override for testing
Run:
python example_02/main.pyKey learning: Frameworks reduce boilerplate and add lifecycle management.
Example 03 - Testing with DI
Shows the PRIMARY benefit of DI: testability with mocks.
| File | Description |
|---|---|
main.py |
Testable implementation with UserService |
test_main.py |
pytest tests demonstrating mock injection |
Run:
python example_03/main.py # Run the example
pytest example_03/test_main.py -v # Run testsKey learning: DI enables isolated, fast, reliable tests.
Interfaces - Protocol Definitions
Shared Protocol definitions used across all examples.
from interfaces import APIClientProtocol, ServiceProtocolKey learning: Protocols enable duck typing with type safety.
python_di_examples/
├── interfaces/ # Protocol definitions (contracts)
│ ├── __init__.py
│ └── protocols.py # APIClientProtocol, ServiceProtocol
├── example_01/ # Fundamentals: coupling vs decoupling
│ ├── __init__.py
│ ├── main_before.py # Anti-pattern (tightly coupled)
│ └── main_di.py # Solution (manual DI)
├── example_02/ # Framework: dependency-injector
│ ├── __init__.py
│ └── main.py # Container, providers, wiring
├── example_03/ # Testing: mocks with DI
│ ├── __init__.py
│ ├── main.py # Testable implementation
│ └── test_main.py # pytest examples
├── .env.example # Environment template
├── .python-version # Python 3.8+
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Development dependencies
└── README.md # This file
# Run all tests
pytest
# Run with verbose output
pytest -v
# Run specific example tests
pytest example_03/test_main.py -v
# Run with coverage (if installed)
pytest --cov=. --cov-report=htmlContributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Follow the documentation standards (Type Hints + Google Docstrings + Protocols)
- Add tests for new functionality
- Submit a pull request
This project is open source and available for educational purposes.