jam*_*sls 15 python python-asyncio
我最初有一些代码将结果汇总到一个列表中.当我重构此代码以使用列表理解时,我得到了意想不到的结果:
import asyncio
@asyncio.coroutine
def coro():
return "foo"
# Writing the code without a list comp works,
# even with an asyncio.sleep(0.1).
@asyncio.coroutine
def good():
yield from asyncio.sleep(0.1)
result = []
for i in range(3):
current = yield from coro()
result.append(current)
return result
# Using a list comp without an async.sleep(0.1)
# works.
@asyncio.coroutine
def still_good():
return [(yield from coro()) for i in range(3)]
# Using a list comp along with an asyncio.sleep(0.1)
# does _not_ work.
@asyncio.coroutine
def huh():
yield from asyncio.sleep(0.1)
return [(yield from coro()) for i in range(3)]
loop = asyncio.get_event_loop()
print(loop.run_until_complete(good()))
print(loop.run_until_complete(still_good()))
print(loop.run_until_complete(huh()))
Run Code Online (Sandbox Code Playgroud)
如果我运行此代码,我得到此输出:
$ python3.4 /tmp/test.py
['foo', 'foo', 'foo']
['foo', 'foo', 'foo']
<generator object <listcomp> at 0x104eb1360>
Run Code Online (Sandbox Code Playgroud)
为什么第三个huh()功能得到不同的结果?
一个修复程序,您的问题将是把next(...)而非...第三功能,或更好的写的回报return list((yield from coro()) for i in range(3))(学分@zch这个想法),甚至更好的与第一功能留下来.
关键是第二个功能不是发电机.它只是一个返回理解生成器的普通函数.
例如,此代码在生成器外部有效:
values = [(yield x) for x in range(3)]
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
next(values)
0
next(values)
1
next(values)
2
next(values)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration: [None, None, None]
Run Code Online (Sandbox Code Playgroud)
@coroutine然后,装饰器通过迭代结果使第二个函数成为生成器,参见此处,第143行.
相比之下,第一个和第三个函数实际上是生成器,而@coroutine装饰器只是返回自己,见这里,第136-137行.在第一种情况下,发电机返回列表(实际上升StopIteration(['foo', 'foo', 'foo'])).在第三种情况下,它返回理解生成器.