2015-03-29 20 views
15

Ban đầu tôi đã có một số mã tổng hợp kết quả vào danh sách. Khi tôi refactored mã này sử dụng một danh sách comphrehension, tôi nhận được kết quả bất ngờ:Tại sao tôi nhận được kết quả khác khi sử dụng danh sách hiểu với coroutines với 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())) 

Nếu tôi chạy mã này tôi nhận được kết quả này:

$ python3.4 /tmp/test.py 
['foo', 'foo', 'foo'] 
['foo', 'foo', 'foo'] 
<generator object <listcomp> at 0x104eb1360> 

Tại sao tôi nhận kết quả khác nhau cho ba huh() chức năng?

+0

[Whoa, nó có thể tái sản xuất.] (Http://ideone.com/k2MsG9) Tôi đã không mong đợi điều đó. Làm sao địa ngục? – user2357112

Trả lời

7

Khắc phục sự cố của bạn là đặt next(...) thay vì ... khi trả lại hàm thứ ba hoặc viết return list((yield from coro()) for i in range(3)) (tín dụng cho @zch cho ý tưởng này) hoặc thậm chí tốt hơn với chức năng đầu tiên.


Vấn đề là chức năng thứ hai không phải là máy phát. Nó chỉ là một hàm bình thường trả về một trình tạo hiểu.

Ví dụ mã này là hợp lệ ngoài máy phát điện:

values = [(yield x) for x in range(3)] 

Sau đó, bạn có thể làm điều này:

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] 

Decorator @coroutine sau đó làm cho chức năng thứ hai một máy phát điện bằng cách duyệt qua kết quả, xem here, dòng 143.

Ngược lại, thứ nhất và thi chức năng thứ ba thực sự là máy phát điện và trang trí @coroutine chỉ trả lại chính mình, xem here, dòng 136-137. Trong trường hợp đầu tiên, danh sách trả về của máy phát (thực tế sẽ tăng lên StopIteration(['foo', 'foo', 'foo'])). Trong trường hợp thứ ba, nó trả về trình tạo hiểu.

+1

Chờ đợi, biểu thức năng suất làm gì bên trong một danh sách hiểu, sau đó? – user2357112

+0

@ user2357112 nó làm cho nó một máy phát điện và không phải là một danh sách. Xem 'type ([(yield x) cho x trong phạm vi (3)])' sẽ cho bạn ''. Đồng thời 'type ([x cho x trong phạm vi (3)])' là ''. – ivanl

+0

Sau khi đào một số, tôi có thể thấy lý do tại sao nó hoạt động theo cách của nó, nhưng điều này thực sự cần phải là một SyntaxError hơn là những gì thực sự xảy ra. Những người biết về hành vi sẽ không sử dụng nó bởi vì nó rất khó hiểu và những người không biết về hành vi đó sẽ nhận được mã không đúng. – user2357112

Các vấn đề liên quan