簡體   English   中英

列表理解和生成器理解之間的區別,其中包含“yield”

[英]Difference between list comprehension and generator comprehension with `yield` inside

有什么用列表內涵和發電機內涵之間的區別yield里面? 兩者都返回一個生成器對象(分別為listcompgenexpr ),但經過全面評估,后者添加了似乎相當多余的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())打印NoneNone (來自append )和[None, None] (來自result )並產生1, 2 您的實際列表也包含那些潛入生成器的None 然而,它被扔掉了,結果又只是一個副作用。 這是實際發生的事情:

  • 在評估列表理解/ listfunc創建生成器。
  • 喂它list迭代它......
    • yield from a的產率的值alist並返回None向理解/ listfunc
    • None存儲在結果列表中
  • 在迭代結束時...

    • return[None, None]的值引發StopIteration
    • list構造函數忽略這一點並將值扔掉
  • 這個故事的寓意

不要yield from理解內部使用yield from 它不會做你認為它會做的事情。

yield from表達式的值為None 您的第二個示例是生成器表達式這一事實意味着它已經從迭代器隱式產生,因此它也將yield from表達式的 yield 的值。 請參閱this以獲得更詳細的答案。

由於混淆並SyntaxError: 'yield' inside list comprehension拋出SyntaxError: 'yield' inside list comprehension這兩個示例在 Python 3.8 中均已棄用。 有關發行說明,請參閱3.8錯誤日志

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM