Context Variables คือตัวแปรที่มีค่าแตกต่างกันไปตาม Context (บริบท) ต่างจาก Thread-Local Storage ที่แต่ละ Thread มีค่าแยกกัน Context Variable อาจมีหลาย Context ใน Thread เดียวกัน เหมาะสำหรับติดตามตัวแปรใน Asynchronous Concurrent Tasks
คลาส ContextVar
ใช้สำหรับประกาศและทำงานกับ Context Variables
import contextvars
name = contextvars.ContextVar("name", default='Hello')
พารามิเตอร์ default จะถูกคืนค่าโดย ContextVar.get() เมื่อไม่พบค่าใน Context ปัจจุบัน
Properties
- name: ชื่อของตัวแปร (Read-only)
Methods
| Method | คำอธิบาย |
|---|---|
get(default=None) | คืนค่าของตัวแปรใน Context ปัจจุบัน ถ้าไม่มี: คืน default argument, หรือ default ของ ContextVar, หรือ Raise LookupError |
set(value) | ตั้งค่าใหม่สำหรับตัวแปรใน Context ปัจจุบัน คืนค่า Token |
reset(token) | คืนค่าเดิมก่อน set() ที่สร้าง Token นั้น |
คลาส Context
Mapping ของ ContextVars ไปยังค่าของพวกเขา
Context(): สร้าง Context ว่างcopy_context(): คัดลอก Context ปัจจุบัน
Method run()
context.run(callable, *args, **kwargs)
รัน callable ใน Context object นี้ การเปลี่ยนแปลง Context Variables จะอยู่ใน Context นี้ Raise RuntimeError ถ้าเรียกจากหลาย OS Thread หรือ Recursive
Methods อื่นๆ
| Method | คำอธิบาย |
|---|---|
copy() | Shallow copy ของ Context object |
context[var] | คืนค่าของ ContextVar var (Raise KeyError ถ้าไม่มี) |
get(var, default=None) | คืนค่าของ var ถ้ามี ไม่งั้นคืน default (หรือ None) |
__iter__() | Iterator over variables ใน Context |
__len__() | จำนวน Variables ใน Context |
keys() | List ของ Variables ทั้งหมด |
values() | List ของค่าทั้งหมด |
items() | List ของ (var, value) pairs |
ตัวอย่างการใช้งาน
import contextvars
import asyncio
request_id = contextvars.ContextVar('request_id')
async def handle_request(req_id):
request_id.set(req_id)
await process_request()
async def process_request():
print(f"Processing request {request_id.get()}")
async def main():
await asyncio.gather(
handle_request('req-1'),
handle_request('req-2'),
handle_request('req-3'),
)
asyncio.run(main())
ผลลัพธ์
Processing request req-1
Processing request req-2
Processing request req-3
แต่ละ Task มี request_id ของตัวเอง แม้รันใน Thread เดียวกัน (asyncio)
เมื่อไหร่ควรใช้
- Async/await code ที่ต้องการส่งผ่านค่าระหว่าง Call stack
- Logging/Tracing ที่ต้องการ Request ID, User ID ตาม Context
- Database connection pooling ต่อ Context
- Configuration ที่เปลี่ยนตาม Request/User