为什么在使用带有asyncio的协同程序的列表解析时会得到不同的结果?

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()功能得到不同的结果?

iva*_*anl 7

一个修复程序,您的问题将是把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'])).在第三种情况下,它返回理解生成器.

  • @ivanl,发电机很棒.问题是列表理解中的`yield`与理解有关,而不是封闭函数.我会称之为虫子. (2认同)
  • 我认为@zch麻痹了我的困惑之源.列表理解中的收益率与列表推导而不是封闭函数绑定.这似乎与此问题相同:http://bugs.python.org/issue10544.请注意Guido的回答,他表示这是不直观的行为,并且可以对其进行更改:http://bugs.python.org/issue10544#msg122759 (2认同)