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 循環的數據類型有以下兩種:
- 一類是集合數據類型,如 list、tuple、dict、set、str 等
- 一類是 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()
變成迭代器的可迭代對象