8.10. Awaitable classes¶
8.10.1. awaitable คืออะไร¶
เมื่อ coroutine เขียน await x ภาษาจะถาม x ว่าจะรอมันอย่างไร อ็อบเจกต์ใดก็ตามที่รู้วิธีตอบคือ awaitable มีสองประเภท:
อ็อบเจกต์ coroutine ที่ฟังก์ชัน
async defคืนค่า การเรียกsend_request()จะสร้างอันหนึ่งทุกครั้ง -- coroutine อ็อบเจกต์ ไม่ใช่ผลลัพธ์ของฟังก์ชัน การเขียนawait send_request()คือสิ่งที่รันเนื้อหาจริงๆอ็อบเจกต์ของ class ที่นิยาม method
__await__async defคือชวเลขสำหรับประเภทแรก__await__คือวิธีด้วยตนเองในการสร้างประเภทที่สอง
โค้ดแอปพลิเคชันใช้ประเภทแรกโดยค่าเริ่มต้น ประเภทที่สองมีอยู่สำหรับกรณีที่หายากที่ อ็อบเจกต์เอง จำเป็นต้องเป็นสิ่งที่ผู้เรียก await, ไม่ใช่ผลลัพธ์ของการเรียก method บนมัน
8.10.2. สองรูปแบบเปรียบเทียบกัน¶
ตรรกะเดียวกันเขียนเป็น coroutine และเป็น awaitable class:
import asyncio
# async def -- almost always the right choice
async def yield_then_return(value):
await asyncio.sleep_ms(0)
return value
# awaitable class -- equivalent, rarely written
class YieldThenReturn:
def __init__(self, value):
self._value = value
def __await__(self):
yield # let the loop run once
return self._value # value of the ``await`` expression
ทั้งสองสามารถ awaitได้ในรูปแบบเดียวกัน:
async def main():
a = await yield_then_return(1)
b = await YieldThenReturn(2)
print(a, b) # prints: 1 2
รูปแบบ async def สั้นกว่า อ่านเหมือน Python ปกติ และให้ภาษาจัดการการบุ๊กคีปปิ้งสำหรับการ suspend-and-resume ทั้งหมด รูปแบบ class ไม่ได้รับอะไรพิเศษในตัวอย่างนี้
8.10.3. เมื่อรูปแบบ class มีคุณค่า¶
เมื่ออ็อบเจกต์ต้อง เป็น บางอย่างที่แอปพลิเคชันส่งต่อกัน -- ไม่ใช่ฟังก์ชันที่ผู้เรียกเรียกเพื่อรับ coroutine -- รูปแบบ class คือตัวเลือกเดียว:
ค่า future-like ที่แอปพลิเคชันสร้าง ส่งให้ producer และ
awaitในภายหลังเพื่อดึงผลลัพธ์ที่ผลิตแล้วprimitive ที่กำหนดเองที่สร้างบน primitive ที่มีอยู่ซึ่ง API ตามธรรมชาติคือ
await my_thingแทนที่จะเป็นawait my_thing.wait()classasyncio.Taskเองเป็นตัวอย่างในตัว -- การเขียนawait taskทำงานได้เพราะTaskนิยาม__await__
สำหรับอะไรก็ตามที่เข้ากับรูปแบบ เรียกฟังก์ชัน รับ coroutine await มัน, async def ชนะ
8.10.4. รายละเอียดโปรโตคอล¶
__await__ เป็น method ปกติ (ไม่ใช่ async def) ที่คืน iterator การเขียนเป็น generator -- รวมถึง yield อย่างน้อยหนึ่งตัวในเนื้อหา -- ทำให้เป็นอันโดยอัตโนมัติ แต่ละ yield จะ suspend coroutine ที่ awaitอ็อบเจกต์และส่งการควบคุมกลับไปยัง event loop generator จะ resume ครั้งถัดไปที่ลูปกำหนดเวลา task return แบบเปล่า (หรือสิ้นสุดโดยไม่มี return) จบการรอ ค่าที่ return ผลิตจะกลายเป็นค่าของ expression await
ในทางปฏิบัติ class ที่หายากที่ทำสิ่งนี้จะส่ง yielding ไปยัง awaitable ที่มีอยู่แทนที่จะขับเคลื่อน loop เอง:
class WaitForEvent:
def __init__(self, event):
self._event = event
def __await__(self):
yield from self._event.wait().__await__()
return self._event
yield from ใช้ __await__ ของ event ที่มีอยู่สำหรับการ suspending จริง แอปพลิเคชัน asyncio ส่วนใหญ่ไม่ต้องการเขียนรูปแบบใดทั้งสอง