Python 生成器 (generator) & 迭代器 (iterator)

python 生成器 & 迭代器

生成器 (generator)

列表生成式

列表生成式用來生成一個列表,雖然寫的是表達式,可是儲存的是計算出來的結果,所以生成的列表受到內存大小的限制
示例:python

a = [x ** 2 for x in range(5)]
print(a)

輸出結果:算法

[0, 1, 4, 9, 16]

生成器 (generator)

生成器一樣能夠用來生成一個列表,可是生成器保存的是算法,在每一次調用 next 時纔會計算出結果,所以生成的列表不會受到內存大小的限制
示例:併發

a = (x ** 2 for x in range(5))
print(a)
for i in range(6):
    print(next(a))

輸出結果:函數

<generator object <genexpr> at 0x107da7870>
0
1
4
9
16
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration

每次調用 next(),就計算出下一個元素的值,沒法再次獲取前面元素的值,直到計算到最後一個元素,沒有更多的元素時,拋出 StopIteration 的錯誤線程

生成器函數

當函數中出現 yield 時這個函數就成了一個 generator 的函數
generator 在執行的時候遇到 yield 時會暫停並保存當前全部的運行信息,返回 yield 的值, 並在下一次執行 next() 方法時從當前位置繼續運行
示例:code

def fib(max_n):
    """斐波那契數列生成器"""
    n, a, b = 0, 0, 1
    while n < max_n:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'


def main():
    f = fib(6)
    while True:
        try:
            x = next(f)
            print(x)
        except StopIteration as e:
            print("Generator return value:", e.value)
            break


if __name__ == '__main__':
    main()

輸出結果:對象

1
1
2
3
5
8
Generator return value: done

經過 yield 實如今單線程的狀況下實現併發運算的效果

示例:內存

import time


def consumer(name):
    print("%s開始吃包子了" % name)    
    while True:
        produce = yield                                # 函數在此暫停,等待喚醒
        print("%s吃了第%i籠包子" % (name, produce+1))      # 喚醒後執行


def producer(name):
    c = consumer("A")
    c2 = consumer("B")
    c.__next__()    
    c2.__next__()
    print("%s準備開始生產" % name)
    for i in range(3):
        time.sleep(1)
        print("已經作了%i籠包子" % (i+1))
        c.send(i)                                       # 將i發送給produce,並喚醒函數
        c2.send(i)

producer("C")

輸出結果:generator

A開始吃包子了
B開始吃包子了
C準備開始生產
已經作了1籠包子
A吃了第1籠包子
B吃了第1籠包子
已經作了2籠包子
A吃了第2籠包子
B吃了第2籠包子
已經作了3籠包子
A吃了第3籠包子
B吃了第3籠包子

在 producer 函數中 c 和 c2 輪流調用 consumer 函數
send()next() 同樣能夠喚醒生成器,並且還能給 yield 傳值it

迭代器 (iterator)

可迭代對象 (iterable)

能夠直接做用於 for 循環的數據類型有如下兩種:

  1. 一類是集合數據類型,如 list、tuple、dict、set、str 等
  2. 一類是 generator,包括生成器和帶 yield 的 generator function
    這些能夠直接做用於 for 循環的對象統稱爲可迭代對象

示例:

def fib(max_n):
    """斐波那契數列生成器"""
    n, a, b = 0, 0, 1
    while n < max_n:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'


def main():
    f = fib(6)
    for i in f:
        print(i)


if __name__ == '__main__':
    main()

輸出結果:

1
1
2
3
5
8

迭代器 (iterator)

能夠被 next() 函數調用並不斷返回下一個值的對象稱爲迭代器
生成器都是 Iterator 對象,但list、dict、str 雖然是 Iterable ,卻不是Iterator
把list、dict、str 等 Iterable 變成 Iterator 可使用 iter() 函數
示例:

a = [1, 2, 3, 4, 5, 6, 7]
b = a.__iter__()
c = iter(a)

print(a, b, c)

輸出結果:

[1, 2, 3, 4, 5, 6, 7] <list_iterator object at 0x11d271f60> <list_iterator object at 0x11d260160>

b, c 都是經過 a 變成的迭代器
a, b, c 均可以使用 for 循環:

for i in a:
    print(i)
for i in b:
    print(i)

結果一致

對比

生成器 (generator) 都是迭代器 (iterator),可是迭代器不必定是生成器,還有經過 iter() 變成迭代器的可迭代對象

相關文章
相關標籤/搜索