接前面 Python 协程小记(一),继续整理Python 协程基础知识。随意记录下自己的纠结点
协程函数写好了:
| async def hello(name):
print(f"Hello {name}!")
|
然后抓瞎了,要执行这个协程,只会用asyncio
:
| import asyncio
asyncio.run(hello("1+1=10"))
|
抛开asyncio
, 竟不知道怎么执行它。乱试一通,通通都不行:
| hello("1+1=10") # RuntimeWarning: coroutine 'hello' was never awaited
hello("1+1=10").send(None) # TypeError: object NoneType can't be used in 'await' expression
await hello("1+1=10") # SyntaxError: 'await' outside function
hello("1+1=10").__await__().send(None) # TypeError: object NoneType can't be used in 'await' expression
next(hello("1+1=10").__await__()) # TypeError: object NoneType can't be used in 'await' expression
|
这个问题让人堵得慌: async def
、await
明明设计上都不依赖 asyncio这个库的。为什么想运行一个小函数这么难...
开始-结束
准备好好挖一下,突然发现上面 hello("1+1=10").send(None)
已经接近答案了,只是看错误提示信息时,漏掉了 StopIteration
这句:
| Hello 1+1=10!
Traceback (most recent call last):
File "C:\Users\dbzha\PycharmProjects\pythonProject2\b.py", line 11, in <module>
hello("1+1=10").send(None) # TypeError: object NoneType can't be used in 'await' expression
^^^^^^^^^^^^^^^^^^^^^^^^^^
StopIteration
|
修改一下,直接可以了:
| async def hello(name):
print(f"Hello {name}!")
try:
f = hello("1+1=10")
f.send(None)
except StopIteration:
pass
|
和生成器(Generate Iterator)一样,我们可以使用send()函数进行驱动。但是和生成器不一样,我们不能用next()驱动它,因为协程没有__next__()
成员。
扩充一下?
加点其他试试?
Awaitable
定义一个 MyAwaitable,可以就可以用await了:
| class MyAwaitable:
def __await__(self):
yield
async def hello():
print(f"Hello begin")
await MyAwaitable()
print(f"Hello end")
|
驱动起来,注意需要2个send():
| try:
f = hello()
f.send(None)
f.send(None)
except StopIteration:
pass
|
从这儿可以看到,需要有个自动机制,来不断触发send()才行
异步迭代器
定义一个异步迭代器看看:
1
2
3
4
5
6
7
8
9
10
11
12
13 | async def debao():
yield 'd'
yield 'e'
yield 'b'
yield 'a'
yield 'o'
async def hello():
print(f"Hello begin")
d = debao()
async for i in d:
print(i)
print(f"Hello end")
|
同样方式驱动:
| try:
f = hello()
f.send(None)
except StopIteration:
pass
|
结果如下:
| Hello begin
d
e
b
a
o
Hello end
|
思考,如果hello()中不用 async for
,会怎么样?:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | async def hello():
print(f"Hello begin")
d = aiter(debao())
print(await anext(d))
print(await anext(d))
print(await anext(d))
print(await anext(d))
print(await anext(d))
print(f"Hello end")
try:
f = hello()
f.send(None)
f.send(None)
f.send(None)
f.send(None)
f.send(None)
except StopIteration:
pass
|
尽管丑陋了很多,结果和之前一样:
| Hello begin
d
e
b
a
o
Hello end
|
还可以再调整一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | async def debao():
yield 'd'
yield 'e'
yield 'b'
yield 'a'
yield 'o'
async def hello():
print(f"Hello begin")
d = aiter(debao())
while True:
try:
print(await anext(d))
except StopAsyncIteration:
break
print(f"Hello end")
if __name__ == '__main__':
try:
f = hello()
while True:
f.send(None)
except StopIteration:
pass
|
...
参考