ContextVar stores a value in the current execution context, allowing tasks to change their binding without overwriting a sibling task’s binding.
Python ContextVar: task-local labels without sharing one global binding
Operation contract
The parent supplies an import label before creating two tasks. Each task receives that context and temporarily binds its own receipt label. After an explicit scheduling yield, each still sees its own value. Resetting its token restores the previous binding, and the parent label remains unchanged after both tasks finish.
Failure and ownership boundary
Context copying copies bindings, not an independent deep graph of every bound object. Binding one mutable dictionary can still expose shared mutation across tasks. Context propagation into thread/process boundaries also depends on the API used. Python asyncio TaskGroup: cancel sibling work and retain failure evidence and Python shallow and deep copies: preserve aliases deliberately explain why task-local names alone do not isolate all state.
Working program
import asyncio
from contextvars import ContextVar
receipt_context = ContextVar("receipt_context", default="unassigned")
async def inspect_receipt(receipt_id):
token = receipt_context.set(receipt_id)
try:
await asyncio.sleep(0)
return receipt_context.get()
finally:
receipt_context.reset(token)
async def inspect_batch():
token = receipt_context.set("batch-DEL")
try:
print(await asyncio.gather(inspect_receipt("R-0041"), inspect_receipt("R-0042")))
print("parent:", receipt_context.get())
finally:
receipt_context.reset(token)
asyncio.run(inspect_batch())
print("outside:", receipt_context.get())Output
['R-0041', 'R-0042']
parent: batch-DEL
outside: unassignedCosts and limits
Context bindings add per-context state while referenced objects retain their own memory costs. This fixture schedules no network or external work. The scheduling yield tests binding separation rather than latency or parallel CPU execution.
Common Mistakes
- Reset a temporary binding using the token returned by set.
- A context-local reference can still point to a shared mutable object.
Connected lessons
Python asyncio TaskGroup: cancel sibling work and retain failure evidence, Python shallow and deep copies: preserve aliases deliberately, Python logging: include bounded context without printing sensitive payloads.
