python生成器
1. 什么是生成器?
生成器(英文名 Generator ),是一個可以像迭代器那樣使用for循環來獲取元素的函數。
生成器的出現(Python 2.2 +),實現了延時計算,從而緩解了在大量數據下內存消耗過猛的問題。
當你在 Python Shell 中敲入一個生成器對象,會直接輸出 generator object
提示你這是一個生成器對象
>>> gen = (i for i in range(5))
>>> gen
at 0x10cae50b0>
2. 如何創建生成器?
使用列表推導式
在上面已經演示過,正常我們使用列表推導式時是下面這樣子,使用 []
,此時生成的是列表。
>>> mylist = [i for i in range(5)]
>>> mylist
[0, 1, 2, 3, 4]
而當你把 []
換成 ()
,返回的就不是列表了,而是一個生成器
>>> gen = (i for i in range(5))
>>> gen
at 0x10cae50b0>
使用 yield
yield
是什么東西呢? 它相當于我們函數里的 return,但與 return 又有所不同。
當一個函數運行到 yield 后,函數的運行會暫停,并且會把 yield 后的值返回出去。
若 yield 沒有接任何值,則返回 None
yield 雖然返回了,但是函數并沒有結束
請看如下代碼,我定義了一個 generator_factory
函數,當我執行 gen = generator_factory()
時,gen 就是一個生成器對象
>>> def generator_factory(top=5):
... index = 0
... while index < top:
... print("index 值為: " + str(index))
... index = index + 1
... yield index
... raise StopIteration
...
>>> gen = generator_factory()
>>> gen
3. 生成器的使用
從一個生成器對象中取出元素,和我們前面學過的通過切片訪問列表中的元素不一樣,它沒有那么直觀。
想要從生成器對象中取出元素,只有兩種方法:
第一種方法:使用 next 方法一個一個地把元素取出來,如果元素全部取完了,生成器會拋出 StopIteration
的異常。
>>> gen = (x for x in range(3))
>>> gen
at 0x1072400b0>
>>> next(gen)
0
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
Traceback (most recent call last):
File "", line 1, in
StopIteration
第二種方法:使用 for 循環一個一個地迭代出來
>>> gen = (x for x in range(3))
>>> for i in gen:
... print(i)
...
0
1
2
4. 生成器的激活
生成器對象,在創建后,并不會執行任何的代碼邏輯。
想要從生成器對象中獲取元素,那么第一步要觸發其運行,在這里稱之為激活。
方法有兩種:
使用next()
:上面已經講過
使用generator.send(None)
還以下面這段代碼為例,可以看到 gen.send(None)
相當于執行了 next(gen)
>>> def generator_factory(top=5):
... index = 0
... while index < top:
... print("index 值為: " + str(index))
... index = index + 1
... yield index
... raise StopIteration
...
>>>
>>> gen = generator_factory()
>>> gen.send(None)
index 值為: 0
1
>>> gen.send(None)
index 值為: 1
2
5. 生成器的狀態
生成器在其生命周期中,會有如下四個狀態
GEN_CREATED
# 生成器已創建,還未被激活
GEN_RUNNING
# 解釋器正在執行(只有在多線程應用中才能看到這個狀態)
GEN_SUSPENDED
# 在 yield 表達式處暫停
GEN_CLOSED
# 生成器執行結束
通過下面的示例可以很輕松地理解這一過程(GEN_RUNNING
這個狀態只有在多線程中才能觀察到,這里就不演示啦)
>>> gen = (x for x in range(2))
>>> from inspect import getgeneratorstate
>>> gen = (x for x in range(3))
>>> getgeneratorstate(gen)
'GEN_CREATED'
>>>
>>> next(gen)
0
>>> getgeneratorstate(gen)
'GEN_SUSPENDED'
>>> next(gen)
1
>>> next(gen)
Traceback (most recent call last):
File "", line 1, in
StopIteration
>>> getgeneratorstate(gen)
'GEN_CLOSED'
6. 生成器的異常
在最前面,我有定義了一個生成器函數。
def generator_factory(top=2):
index = 0
while index < top:
index = index + 1
yield index
raise StopIteration
在沒有元素可返回時,我最后拋出了 StopIteration
異常,這是為了滿足生成器的協議。
實際上,如果你不手動拋出 StopIteration
,在生成器遇到函數 return 時,會我自動拋出 StopIteration
。
請看下面代碼,我將 raise StopIteration
去掉后,仍然會拋出異常。
>>> def generator_factory(top=2):
... index = 0
... while index < top:
... index = index + 1
... yield index
...
>>> gen = generator_factory()
>>> next(gen)
1
>>> next(gen)
2
>>> next(gen)
Traceback (most recent call last):
File "", line 1, in
StopIteration
審核編輯:符乾江
-
生成器
+關注
關注
7文章
315瀏覽量
21002 -
python
+關注
關注
56文章
4792瀏覽量
84627
發布評論請先 登錄
相關推薦
評論