Skip to content

[Python] yield 與生成器

Last Updated on 2023-07-11 by Clay

介紹

yield 是 Python 中的一個關鍵字,它的使用場景與 return 很像,不過使用 yield 會把函式變成一個生成器generator)。

什麼是生成器呢?生成器可以想像成一個更加簡單直接的迭代器iterator),它的主要優點是可以延遲計算與延遲生成返回值,也就是說每次調用生成器函式迭代時才會進行運算。這對於大量級的計算或無窮數列來說非常有用 —— 至少你不用一次性地將所有資料載入記憶體

以下來看個簡單的例子。


yield 與 next() 範例程式碼

除了直接用 for 迴圈取值外,我們也可以使用 iter() 搭配 next() 來取值。

直得一提的是,每次呼叫 infinite_sequence() 時都會創建一個新的生成器,所以才會看到兩次從 1 開始的數字。

# coding: utf-8
from typing import Iterator


def infinite_sequence() -> Iterator[int]:
    num = 0
    while True:
        num += 1
        yield num


def main() -> None:
    # For Loop
    for i in infinite_sequence():
        print("for", i)

        if i >= 5:
            break

    # Next
    sequence_iterator = iter(infinite_sequence())
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))


if __name__ == "__main__":
    main()


Output:

for 1
for 2
for 3
for 4
for 5
next 1
next 2
next 3
next 4
next 5


如果要看到同樣的數字,則要在一開始就將其包成迭代器。

# coding: utf-8
from typing import Iterator


def infinite_sequence() -> Iterator[int]:
    num = 0
    while True:
        num += 1
        yield num


def main() -> None:
    # Init
    sequence_iterator = iter(infinite_sequence())

    # For Loop
    for i in sequence_iterator:
        print("for", i)

        if i >= 5:
            break

    # Next
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))
    print("next", next(sequence_iterator))


if __name__ == "__main__":
    main()


Output:

for 1
for 2
for 3
for 4
for 5
next 6
next 7
next 8
next 9
next 10

在第二個版本中,我們會看到使用 for 迴圈與 next() 都是對同一個迭代器了。


References


Read More

Tags:

Leave a Reply