Understanding Scopes¶
Scopes control how long service instances live and when they're created.
What are Scopes?¶
A scope defines the lifecycle of a service: - When it's created - How long it lives - Whether instances are shared
Built-in Scopes¶
Singleton - One Instance Forever¶
from injectq import singleton, InjectQ
@singleton
class Database:
def __init__(self):
print("Database created")
container = InjectQ.get_instance()
# Created once, reused everywhere
db1 = container[Database]
db2 = container[Database]
assert db1 is db2 # True
Use for: Database connections, configuration, caches, loggers
Transient - New Instance Every Time¶
from injectq import transient
import uuid
@transient
class RequestHandler:
def __init__(self):
self.id = uuid.uuid4()
# New instance each time
handler1 = container[RequestHandler]
handler2 = container[RequestHandler]
assert handler1 is not handler2 # True
Use for: Request handlers, validators, temporary objects
Scoped - One Instance Per Scope¶
from injectq import scoped
@scoped("request")
class UserSession:
def __init__(self):
self.user_id = None
# One instance within a scope
async with container.scope("request"):
session1 = container[UserSession]
session2 = container[UserSession]
assert session1 is session2 # True
# New scope = new instance
async with container.scope("request"):
session3 = container[UserSession]
assert session1 is not session3 # True
Use for: Request context, user sessions, transaction data
Choosing the Right Scope¶
| Scope | When to Use | Examples |
|---|---|---|
| Singleton | Shared across app | Database, Config, Cache |
| Transient | Stateless operations | Validators, Handlers |
| Scoped | Per-request state | Session, Context |
Working with Scopes¶
Creating Scopes¶
from injectq import InjectQ
container = InjectQ.get_instance()
# Sync scope
with container.scope("request"):
service = container[RequestService]
# Async scope
async with container.scope("request"):
service = await container.aget(AsyncService)
Clearing Scopes¶
# Clear specific scope
container.clear_scope("request")
# Clear all scopes
container.clear_all_scopes()
Common Mistakes¶
❌ Wrong: Singleton with Request Data¶
✅ Right: Scoped for Request Data¶
@scoped("request")
class UserContext:
def __init__(self):
self.user_id = None # Isolated per request
❌ Wrong: Transient for Expensive Resources¶
@transient
class DatabaseConnection:
def __init__(self):
self.conn = create_connection() # Created every time!
✅ Right: Singleton for Expensive Resources¶
@singleton
class DatabaseConnection:
def __init__(self):
self.conn = create_connection() # Created once
Summary¶
- Singleton → One instance app-wide (databases, config)
- Transient → New instance each time (validators, handlers)
- Scoped → One instance per scope (request context, sessions)
Choose based on: - Data sharing needs - Resource costs - Thread safety requirements
Next: Singleton Scope | Transient Scope | Scoped Services