Mik*_*mov 28 python python-3.x async-await python-asyncio
PEP 0492增加了新的__await__魔法.实现此方法的对象变为类似未来的对象,可以等待使用await.很明显:
import asyncio
class Waiting:
def __await__(self):
yield from asyncio.sleep(2)
print('ok')
async def main():
await Waiting()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)
好的,但如果我想调用一些已async def定义的函数而不是asyncio.sleep?我不能使用await因为__await__不是async函数,我无法使用yield from因为本机协同程序需要await表达式:
async def new_sleep():
await asyncio.sleep(2)
class Waiting:
def __await__(self):
yield from new_sleep() # this is TypeError
await new_sleep() # this is SyntaxError
print('ok')
Run Code Online (Sandbox Code Playgroud)
我该如何解决?
And*_*lov 33
使用直接__await__()电话:
async def new_sleep():
await asyncio.sleep(2)
class Waiting:
def __await__(self):
return new_sleep().__await__()
Run Code Online (Sandbox Code Playgroud)
该解决方案由Yury Selivanov(PEP 492的作者)推荐用于aioodbc库
Sil*_*eak 15
短版:await foo可以替换为yield from foo.__await__()
结合其他答案的所有想法 -
在最简单的情况下,只需委托另一个等待的作品:
def __await__(self):
return new_sleep().__await__()
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为该__await__方法返回一个迭代器(参见PEP 492),因此返回另一个__await__迭代器是正常的.
当然,这意味着我们根本无法改变原始等待的暂停行为.更通用的方法是镜像await关键字并使用yield from- 这使我们可以将多个等待的迭代器组合成一个:
def __await__(self):
# theoretically possible, but not useful for my example:
#yield from something_else_first().__await__()
yield from new_sleep().__await__()
Run Code Online (Sandbox Code Playgroud)
这里有一个问题:这与第一个变体没有完全相同!yield from是一个表达式,所以要做到和以前完全一样,我们还需要返回该值:
def __await__(self):
return (yield from new_sleep().__await__())
Run Code Online (Sandbox Code Playgroud)
这直接反映了我们如何使用await语法编写正确的委托:
return await new_sleep()
Run Code Online (Sandbox Code Playgroud)
额外的一点 - 这两者有什么区别?
def __await__(self):
do_something_synchronously()
return new_sleep().__await__()
def __await__(self):
do_something_synchronously()
return (yield from new_sleep().__await__())
Run Code Online (Sandbox Code Playgroud)
第一个变量是一个普通函数:当你调用它时,do_...执行它并返回一个迭代器.第二个是发电机功能; 调用它根本不执行任何代码!只有在第一次生成返回的迭代器时才会do_...执行.这在以下方面有所不同,有点人为的情况:
def foo():
tmp = Waiting.__await__()
do_something()
yield from tmp
Run Code Online (Sandbox Code Playgroud)
要在__await__函数内部等待,请使用以下代码:
async def new_sleep():
await asyncio.sleep(1)
class Waiting:
def __await__(self):
yield from new_sleep().__await__()
print('first sleep')
yield from new_sleep().__await__()
print('second sleep')
return 'done'
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我不能从本地协同程序产生里面__await__,不过貌似有可能从发电机产生协程内部__await__和收益率从本地协同程序里面产生协同程序。有用:
async def new_sleep():
await asyncio.sleep(2)
class Waiting:
def __await__(self):
@asyncio.coroutine
def wrapper(coro):
return (yield from coro)
return (yield from wrapper(new_sleep()))
Run Code Online (Sandbox Code Playgroud)
使用装饰器。
def chain__await__(f):
return lambda *args, **kwargs: f(*args, **kwargs).__await__()
Run Code Online (Sandbox Code Playgroud)
然后编写__await__为原生协程。
async def new_sleep():
await asyncio.sleep(2)
class Waiting:
@chain__await__
async def __await__(self):
return await new_sleep()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6410 次 |
| 最近记录: |