2015-03-29 20 views
15

İlk olarak, sonuçların bir araya getirildiği bazı kodlar vardı. Bir liste comphrehension kullanmak için bu kodu refactored, ben beklenmeyen sonuçlar alıyorum:Asyncio'lu koroutinler ile liste anlaşılırken neden farklı sonuçlar elde ediyorum?

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

Neden üçüncü huh() için farklı sonuçlar alabilirim: Bu kodu çalıştırırsanız

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())) 

Bu çıktıyı almak işlev?

+0

[Whoa, tekrarlanabilir.] (Http://ideone.com/k2MsG9) Bunu beklemiyordum. Nasıl olur? – user2357112

cevap

7

sorununuza bir düzeltme (bu fikir için @zch kredilerin) Üçüncü işlevi, ya da daha iyi yazma return list((yield from coro()) for i in range(3)) dönüşüne next(...) yerine ... koymak olacağını, hatta daha iyi ilk fonksiyonu ile kal.


Buradaki nokta, ikinci işlevin bir jeneratör olmamasıdır. Bir anlama jeneratörü döndüren sıradan bir işlevdir. ,

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] 

Dekoratör @coroutine sonra jeneratör sonucu üzerinde yineleme tarafından ikinci işlevi yapar:

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

Sonra bunu yapabilirsiniz:

Örneğin bu kod geçerli dışında jeneratör Bkz. here, satır 143.

Aksine, ilk ve thi rd işlevleri aslında jeneratörlerdir ve @coroutine dekoratör sadece kendilerini geri döndürür, bkz. here, satır 136-137. İlk durumda jeneratör, liste döndürür (fiili olarak StopIteration(['foo', 'foo', 'foo'])'u yükseltir). Üçüncü durumda, anlama jeneratörünü döndürür.

+1

Bekleyin, bir getiri ifadesi liste kavramasının içinde ne yapar? – user2357112

+0

@ user2357112 bunu bir jeneratör değil, bir liste yapar. '(X (menzil) için x (x (verim x) 'ye bakınız.)' '' '' Class' generator '> 'verecektir. Aynı zamanda 'tür ([x (x) aralığında x (x)])' 'dır. – ivanl

+0

Bazı kazma işleminden sonra neden böyle çalıştığını anlayabiliyorum, ancak bunun gerçekten gerçekleşenden çok bir SyntaxError olması gerekiyor. Davranış hakkında bilenler bunu kullanmayacak çünkü çok kafa karıştırıcı ve bunu bilmeyen insanlar sessizce yanlış kod alacaklar. – user2357112

İlgili konular