[英]Difference between list comprehension and generator comprehension with `yield` inside
有什么用列表內涵和發電機內涵之間的區別yield
里面? 兩者都返回一個生成器對象(分別為listcomp
和genexpr
),但經過全面評估,后者添加了似乎相當多余的None
s。
>>> list([(yield from a) for a in zip("abcde", itertools.cycle("12"))])
['a', '1', 'b', '2', 'c', '1', 'd', '2', 'e', '1']
>>> list(((yield from a) for a in zip("abcde", itertools.cycle("12"))))
['a', '1', None, 'b', '2', None, 'c', '1', None, 'd', '2', None, 'e', '1', None]
怎么來的? 科學解釋是什么?
TLDR:生成器表達式使用隱式yield
,它從yield from
表達式返回None
。
實際上,這里有兩件事表現不同。 你的列表理解實際上被拋棄了......
如果將表達式轉換為等效函數,則最容易理解這一點。 為了清楚起見,讓我們寫出來:
listcomp = [<expr> for a in b]
def listfunc():
result = []
for a in b:
result.append(<expr>)
return result
gencomp = (<expr> for a in b)
def genfunc():
for a in b:
yield <expr>
要復制初始表達式,關鍵是將<expr>
替換為(yield from a)
。 這是一個簡單的文本替換:
def listfunc():
result = []
for a in b:
result.append((yield from a))
return result
def genfunc():
for a in b:
yield (yield from a)
使用b = ((1,), (2,))
,我們期望輸出1, 2
。 事實上,兩者都復制了各自表達/理解形式的輸出。
正如其他地方所解釋的, yield (yield from a)
應該讓你懷疑。 然而, result.append((yield from a))
應該讓你畏縮......
我們先來看看發電機。 另一個重寫使發生的事情變得很明顯:
def genfunc():
for a in b:
result = (yield from a)
yield result
要使其有效, result
必須有一個值 - 即None
。 生成器不yield
(yield from a)
表達式,而是它的結果。 你只能得到的內容a
作為計算表達式的副作用。
如果您檢查“列表理解”的類型,則它不是list
- 它是generator
。 <listcomp>
只是它的名字。 是的,那不是月亮,而是一個功能齊全的發電機。
還記得我們的轉換是如何yield from
函數內部放置一個yield from
的嗎? 是的,這就是你定義生成器的方式! 這是我們的函數版本,這次是print
在上面的:
def listfunc():
result = []
for a in b:
result.append((yield from a))
print(result[-1])
print(result)
return result
評估list(listfunc())
打印None
、 None
(來自append
)和[None, None]
(來自result
)並產生1, 2
。 您的實際列表也包含那些潛入生成器的None
! 然而,它被扔掉了,結果又只是一個副作用。 這是實際發生的事情:
listfunc
創建生成器。list
迭代它......
yield from a
的產率的值a
到list
並返回None
向理解/ listfunc
None
存儲在結果列表中在迭代結束時...
return
以[None, None]
的值引發StopIteration
list
構造函數忽略這一點並將值扔掉這個故事的寓意
不要yield from
理解內部使用yield from
。 它不會做你認為它會做的事情。
yield from
表達式的值為None
。 您的第二個示例是生成器表達式這一事實意味着它已經從迭代器隱式產生,因此它也將yield from
表達式的 yield 的值。 請參閱this以獲得更詳細的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.