2012-09-07 22 views
5

我與發電機及發電機表達玩弄,我不能完全肯定,我瞭解他們的工作(some reference material):試圖瞭解產量爲表達

>>> a = (x for x in range(10)) 
>>> next(a) 
0 
>>> next(a) 
1 
>>> a.send(-1) 
2 
>>> next(a) 
3 

所以看起來generator.send是忽略。這是有道理的(我猜),因爲沒有明確的yield表達趕發送信息......

然而,

>>> a = ((yield x) for x in range(10)) 
>>> next(a) 
0 
>>> print next(a) 
None 
>>> print next(a) 
1 
>>> print next(a) 
None 
>>> a.send(-1) #this send is ignored, Why? ... there's a yield to catch it... 
2 
>>> print next(a) 
None 
>>> print next(a) 
3 
>>> a.send(-1) #this send isn't ignored 
-1 

我明白這是相當遠在那裏,我(現在)能「T認爲用例這個的(所以不要問;)

我大多隻是探索,試圖找出這些不同的發電機工作方法(以及如何在一般的發電機表達式工作)如何。爲什麼我的第二個例子在產生一個合理的價值和None之間交替?另外,任何人都可以解釋爲什麼我的一個generator.send的被忽略,而另一個不是?

+1

檢查此鏈接是否可以幫助您... http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained –

回答

3

的混亂這裏是發電機表達是做一個隱藏yield。這是函數形式:

def foo(): 
    for x in range(10): 
     yield (yield x) 

當你做一個.send(),會發生什麼是內yield x得到執行,這將產生x。然後表達式評估爲.send的值,然後下一個收益率產生該值。這更清楚形式:

def foo(): 
    for x in range(10): 
     sent_value = (yield x) 
     yield sent_value 

因此,輸出是很容易預測:

>>> a = foo() 
#start it off 
>>> a.next() 
0 
#execution has now paused at "sent_value = ?" 
#now we fill in the "?". whatever we send here will be immediately yielded. 
>>> a.send("yieldnow") 
'yieldnow' 
#execution is now paused at the 'yield sent_value' expression 
#as this is not assigned to anything, whatever is sent now will be lost 
>>> a.send("this is lost") 
1 
#now we're back where we were at the 'yieldnow' point of the code 
>>> a.send("yieldnow") 
'yieldnow' 
#etc, the loop continues 
>>> a.send("this is lost") 
2 
>>> a.send("yieldnow") 
'yieldnow' 
>>> a.send("this is lost") 
3 
>>> a.send("yieldnow") 
'yieldnow' 

編輯:實施例的使用情況。到目前爲止,迄今爲止最酷的一個是twisted的inlineCallbacks函數。 See here爲解釋它的文章。它的核心是它可以讓函數在線程中運行,一旦函數完成,twisted會將函數的結果返回到代碼中。因此,您可以編寫代碼,以非常線性和直觀的方式嚴重依賴線程,而不必在整個地方編寫大量小函數。

請參閱PEP 342瞭解更多關於.send與潛在用例(我提供的扭曲示例是提供此異步提供的異步I/O的示例)的基本原理。

+0

謝謝,這是非常有益的。 – mgilson

+0

嗯......我想你可以用這個將'['a','c','e']'和'['b','d','f']'加入到'[' a','b','c','d','e','f']'... – mgilson

+0

@mgilson:您也可以使用'+'。我會很快更新我的答案在一個很好的使用案例 – Claudiu

2

該發電機轉換成:

for i in xrange(10): 
    x = (yield i) 
    yield x 

結果第二個電話的發送()/下一個()被忽略,因爲你什麼都不做,收益率的一個結果。

2

您有點困惑,因爲您實際上是從兩個來源生成的:生成器表達式(... for x in range(10))是一個生成器,但您使用yield創建另一個來源。你可以看到,如果做到list(a),你會得到[0, None, 1, None, 2, None, 3, None, 4, None, 5, None, 6, None, 7, None, 8, None, 9, None]

您的代碼等效於此:

>>> def gen(): 
...  for x in range(10): 
...   yield (yield x) 

只有內產率(「屈服X」)被「使用」,在發電機---它被用作外產量的值。因此,這個生成器在產生範圍值之間來回迭代,併產生任何「發送」到這些收益率的東西。如果您向內部收益發送某些內容,則會將其返回,但如果您碰巧發送了偶數次迭代,則發送將發送到外部收益並被忽略。

+0

我沒有創建2個生成器 - 我創建了1個生成器和2個yield語句;-)(顯然) – mgilson

+0

你是對的,更好的方式來說這是你從兩個來源生成的。 – BrenBarn

+0

當我意識到「yield」是一個表達式(不是一個聲明)時,它只是把我吹走了。所以我開始玩耍,試圖找出我可以*實際上做的知識* ... – mgilson

-1

事實上 - send方法是爲了與一個生成器對象一起工作,該對象是您明確寫入的一個協同例程的結果。在生成器表達式中很難獲得一些意義 - 儘管它有效。

- 編輯 - 我以前寫的這一點,但它是incorrecct,如發電機表達式中的產量都在不同的實現可預測的 - 儘管在任何PEP沒有提到。

generator expressions are not meant to have the yield keyword - I am not shure the behavior is even defined in this case. We could think a little and get to what is happening on your expression, to meet from where those "None"s are coming from. However, assume that as a side effect of how the yield is implemented in Python (and probably it is even implementation dependent), not as something that should be so.

正確的形式用於發電機表達,以簡化的方式是:

(<expr> for <variable> in <sequence> [if <expr>]) 

所以,<expr>是在<sequence:各值來評價 - 不僅是yield uneeded,因爲你不應該用它。

兩個yieldsend方法意在全協程中使用,是這樣的:

def doubler(): 
    value = 0 
    while value < 100: 
     value = 2 * (yield value) 

而且你可以用它喜歡:

>>> a = doubler() 
>>> # Next have to be called once, so the code will run up to the first "yield" 
... 
>>> a.next() 
0 
>>> a.send(10) 
20 
>>> a.send(20) 
40 
>>> a.send(23) 
46 
>>> a.send(51) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> 
+0

Down voteer care to comment? – jsbueno

+1

。 「生成器表達式並不意味着有yield關鍵字 - 我不確定這種情況下甚至定義了行爲。」它的定義非常完美。看[這個pastebin](http://pastebin.com/Yq6XeTUg)。這有點奇怪,但它確實有道理。 – Claudiu

+0

None不是來自實現相關的東西,只是他正在產生Nones(調用.next(),它將None發送到yield) – Claudiu

0

你寫的發電機相當於更詳細:

def testing(): 
    for x in range(10): 
      x = (yield x) 
      yield x 

正如你所見,她e,第二個yield(隱含在生成器表達式中)不會保存您傳遞它的值,因此取決於生成器執行被阻止的位置,send可能工作也可能不工作。