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


python 生成器 & 迭代器

生成器 (generator)

列表生成式

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

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() 方法時從當前位置繼續運行
示例:

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")

輸出結果:

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 傳值

迭代器 (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() 變成迭代器的可迭代對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM