2015-03-29 12 views
15

शुरू में मेरे पास कुछ कोड था जो परिणामों को एक सूची में एकत्रित करता था। जब मैं एक सूची comphrehension उपयोग करने के लिए इस कोड को पुनर्संशोधित, मैं अप्रत्याशित परिणाम हो रही है:asyncio के साथ coroutines के साथ सूची समझ का उपयोग करते समय मुझे अलग-अलग परिणाम क्यों मिल रहे हैं?

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

मैं तीसरे huh() के लिए अलग-अलग परिणाम क्यों मिलता है:

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

अगर मैं इस कोड को चलाने मैं इस आउटपुट प्राप्त समारोह?

+0

[वाह, यह पुनरुत्पादित है।] (Http://ideone.com/k2MsG9) मुझे इसकी उम्मीद नहीं थी। कैसे ये? – user2357112

उत्तर

7

आपकी समस्या का फिक्स तीसरे समारोह, या बेहतर लिखने return list((yield from coro()) for i in range(3)) की वापसी में next(...) बजाय ... डाल करने के लिए (क्रेडिट इस विचार के लिए @zch करने के लिए) होगा, या और भी बेहतर पहले समारोह के साथ रहते हैं।


बिंदु यह है कि दूसरा कार्य जनरेटर नहीं है। यह सिर्फ एक साधारण कार्य है जो एक समझ जनरेटर देता है।

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

तो फिर तुम यह कर सकते हैं:

उदाहरण के लिए इस कोड को मान्य बाहर जनरेटर है

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] 

डेकोरेटर @coroutine तो परिणाम पर पुनरावृत्ति से एक जनरेटर दूसरा समारोह में आता है, here देखें, लाइन 143.

इसके विपरीत, पहला और थाई rd फ़ंक्शन वास्तव में जेनरेटर हैं, और @coroutine सजावटी बस खुद को लौटते हैं, here देखें, लाइन 136-137। पहले मामले में जनरेटर सूची लौटाता है (वास्तव में StopIteration(['foo', 'foo', 'foo']) उठाता है)। तीसरे मामले में यह समझ जनरेटर लौटाता है।

+1

रुको, उपज अभिव्यक्ति एक सूची समझ के अंदर क्या करती है, फिर? – user2357112

+0

@ user2357112 यह इसे जनरेटर बनाता है और सूची नहीं। X में श्रेणी के लिए 'प्रकार ([(उपज x) देखें (3)]' 'आपको' 'देगा। उसी समय 'प्रकार ([x x में श्रेणी x (3)])' 'class 'list'>' है। – ivanl

+0

कुछ खोदने के बाद, मैं देख सकता हूं कि यह किस तरह से काम करता है, लेकिन वास्तव में वास्तव में क्या होता है इसके बजाय इसे वास्तव में एक सिंटेक्स त्रुटि होना चाहिए। जो लोग व्यवहार के बारे में जानते हैं वे इसका उपयोग नहीं करेंगे क्योंकि यह इतना भ्रमित है, और जो लोग इसके बारे में नहीं जानते हैं वे चुपचाप गलत कोड प्राप्त करेंगे। – user2357112

संबंधित मुद्दे