Skip to content

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

@singleton
class UserContext:
    def __init__(self):
        self.user_id = None  # Shared across all requests!

✅ 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