2014-07-21 34 views
2

我有一個簡單的協同程序爲什麼這個協程永遠生成None值?

def id(): 
    while True: 
     x = yield 
     yield x 

我可以用它來創建一個發電機和總理將其與next

gen = id() 
next(gen) 

for x in gen: 
    print(x) 

這將打印None永遠。我的直覺是,id的發生器只有yield值,一旦它的值爲sent,但在這種情況下,它自己產生的值都是None

有人可以向我解釋這種行爲嗎? x = yield聲明是否違約xNone

回答

3

正如其他人所指出的那樣,叫next(gen)相當於調用gen.send(None)。你可以看到這一點,如果你看一下C code for generator objects

PyDoc_STRVAR(send_doc, 
"send(arg) -> send 'arg' into generator,\n\ 
return next yielded value or raise StopIteration."); 

PyObject * 
_PyGen_Send(PyGenObject *gen, PyObject *arg) 
{ 
    return gen_send_ex(gen, arg, 0); 
} 
... 
static PyObject * 
gen_iternext(PyGenObject *gen) 
{ 
    return gen_send_ex(gen, NULL, 0); 
} 

正如你所看到的,iternext(這是當你調用next(generator_object)什麼被調用),調用完全相同的方法generator_object.send,只有它總是通過在NULL對象。想想看,你的for x in gen循環基本上是這樣做的相當於:

iterable = iter(gen): 
while True: 
    try: 
     x = next(iterable) 
    except StopIteration: 
     break 
    print(x) 

,您將看到的問題是什麼。

認識到協程和發生器是真正完全獨立的概念是很重要的,儘管它們都是使用yield關鍵字實現的。一般來說,你不應該迭代一個協程,並且通常你不需要/想將send的東西放入一個生成器中。我強烈推薦David Beazley的PyCon coroutine tutorial以獲取更多關於此和一般協程的信息。

2

for聲明調用next方法的發生器,而不是send方法。根據文檔(Python的2.7),這導致在yield語句,返回無:

generator.next()

啓動發電機功能的執行或 在最後執行的yield表達恢復它。當發生器 功能以next()方法重新開始時,當前的yield表達式 總是計算爲None

0

yield是一個僅在函數內有效的表達式。 yield表達式的值是None。所以你的函數產生None,然後將yield的結果(None)分配給x,然後產生x。爲了更好地展示發生的事情,讓我們從第一個產出中產生一些東西,看看會發生什麼。

def id(): 
    while True: 
     x = yield 5 
     yield x 

現在,這將產生以下順序:

5 
None 
5 
None 
5 
None 
5 
None 
... 
相關問題