Python __await__ 方法
最后修改于 2025 年 4 月 8 日
本综合指南探讨了 Python 的 __await__ 方法,这是一个使对象可等待的特殊方法。我们将介绍异步编程、协程、可等待对象以及实践示例。
基本定义
__await__ 方法返回一个迭代器,该迭代器用于实现可等待对象。它允许一个对象在异步函数中与 await 表达式一起使用。
主要特征:它必须返回一个迭代器,被 async/await 语法使用,并启用自定义的可等待对象。它是 Python 3.5 中引入的 Python 异步编程模型的一部分。
基本 __await__ 实现
这是一个简单的实现,展示了 __await__ 如何使自定义对象可等待。该方法必须返回一个迭代器。
class SimpleAwaitable:
def __await__(self):
yield
return "Done"
async def main():
result = await SimpleAwaitable()
print(result) # Output: Done
import asyncio
asyncio.run(main())
此示例创建一个基本的可等待对象。__await__ 方法 yield 一次并返回一个值。当被 await 时,它会暂停执行,直到 yield 完成。
yield 至关重要 - 它使该方法成为生成器,这是 __await__ 所必需的。返回值成为 await 表达式的结果。
具有异步操作的可等待对象
此示例展示了一个更实用的可等待对象,它模拟了具有延迟的异步操作。
class AsyncOperation:
def __init__(self, delay):
self.delay = delay
def __await__(self):
yield from asyncio.sleep(self.delay)
return f"Completed after {self.delay}s"
async def main():
op = AsyncOperation(1.5)
print("Starting operation")
result = await op
print(result)
asyncio.run(main())
此可等待对象使用 asyncio.sleep 来模拟异步操作。yield from 委托给另一个可等待对象。
当被 await 时,它会在返回完成消息之前暂停执行指定的延迟。这种模式对于包装异步操作很常见。
自定义 Future 实现
此示例演示如何使用 __await__ 实现一个基本的类似 Future 的对象,该对象可以在以后设置结果。
class CustomFuture:
def __init__(self):
self._result = None
self._done = False
def set_result(self, result):
self._result = result
self._done = True
def __await__(self):
while not self._done:
yield
return self._result
async def set_future(future, delay, value):
await asyncio.sleep(delay)
future.set_result(value)
async def main():
future = CustomFuture()
asyncio.create_task(set_future(future, 2, "Future result"))
print("Waiting for future...")
result = await future
print(f"Got: {result}")
asyncio.run(main())
这个 CustomFuture 可以被 await,直到它的结果被设置。__await__ 方法 yield,直到 _done 变为 True,然后返回结果。
这模仿了真正的 Futures 在 asyncio 中的工作方式,允许解耦的结果设置和等待。此模式对于将基于回调的 API 与异步连接起来非常有用。
链式可等待对象
此示例展示了如何使用 __await__ 将多个可等待对象链接在一起。
class AddAwaitable:
def __init__(self, a, b):
self.a = a
self.b = b
def __await__(self):
result = yield from self.a.__await__()
result += yield from self.b.__await__()
return result
async def slow_add(a, b):
await asyncio.sleep(1)
return a + b
async def main():
a = slow_add(10, 20)
b = slow_add(30, 40)
combined = AddAwaitable(a, b)
result = await combined
print(f"Total: {result}") # Output: Total: 100
asyncio.run(main())
AddAwaitable 类链接了两个可等待对象,并将它们的结果相加。它使用 yield from 依次 await 每个操作数。
这演示了 __await__ 如何将多个异步操作组合成新的可等待对象。此模式对于构建复杂的异步工作流非常有用。
带有 __await__ 的异步上下文管理器
此示例使用 __await__ 实现了一个异步上下文管理器,用于资源管理。
class AsyncResource:
def __init__(self, name):
self.name = name
async def __aenter__(self):
print(f"Opening {self.name}")
await asyncio.sleep(0.5)
return self
async def __aexit__(self, *args):
print(f"Closing {self.name}")
await asyncio.sleep(0.5)
def __await__(self):
return self.__aenter__().__await__()
async def main():
async with AsyncResource("DB Connection") as resource:
print(f"Using {resource.name}")
await asyncio.sleep(1)
# Alternative using await directly
resource = await AsyncResource("File")
try:
print(f"Using {resource.name}")
await asyncio.sleep(1)
finally:
await resource.__aexit__(None, None, None)
asyncio.run(main())
这展示了使用异步资源的两种方法:使用 async with 和直接使用 await。__await__ 方法委托给 __aenter__。
当您需要上下文管理器和直接 await 支持时,此模式很有用。它演示了 __await__ 如何与其他异步协议集成。
最佳实践
- 始终返回一个迭代器:
__await__必须返回一个迭代器 - 使用 yield 或 yield from: 需要使该方法成为生成器
- 考虑取消: 适当处理 asyncio.CancelledError
- 记录 await 行为: 清楚地记录 await 的作用
- 首选 async def 用于协程: 仅将 __await__ 用于自定义可等待对象
资料来源
作者
列出所有 Python 教程。