Python之叠代器
一、叠代器
有時候我們在定義一個列表的時候,列表中的元素是具有一定規則的,這時候可以用列表生成式來提高一下我們的逼格。具體語法如下:
1 list = [i*3 for i in range(10)] #列表生成式 等價於 list = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
2 print(list) #[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
理解了列表生成式的語法,生成器的寫法就很容易了,只要將[]改成()即可,生成器的語法如下:
1 list_generate = (i*3 for i in range(10)) #列表生成器 2 print(list_generate) #執行結果<generator object <genexpr> at 0x03327C30>
列表生成式是在執行程序之前,就將數據生成並存放在內存中,而生成器是一個算法,只有程序在執行的過程中才會生成當前所需要的數據。下圖是這兩種方式在內存的存儲方式:
因此可以得出兩種的區別:1、列表生成式占用內存,取的速度快 2、生成器占用很少內存,取的速度慢
對於生成器而言,要想獲取生成器中的元素,需要每次調用其__next__()方法,如果我們的生成器有100萬條數據,那我敢肯定你一定會瘋掉的,因此我們一般用循環來取生成器中的數據,例如:
1 list_generate = (i*3 for i in range(10)) #列表生成器 2 for i in list_generate: 3 print(i)
函數生成器
使用關鍵字yield定義生成器。
1 def getNo(): 2 for i in range(10): 3 yield i 4 f = getNo() 5 print(f.__next__())
其中f就是一個生成器,下面我們利用函數生成器來實現單線程下的並發效果(著名的生產者消費者模式)。
1 import time 2 def consmer(name):3 print("%s準備吃包子了。" % name) 4 while True: 5 baozi = yield 6 print("%s號包子來了,被%s吃了" % (baozi, name)) 7 def producter(name): 8 eat_p = consmer("吃貨") 9 eat_p1 = consmer("餓貨") 10 eat_p.__next__() 11 eat_p1.__next__() 12 for i in range(1,100,2): 13 print("老子開始做包子了") 14 time.sleep(2) 15 print("%s做了2個包子" % name) 16 eat_p.send(i-1) 17 eat_p1.send(i) 18 producter("高文祥")
Iterable(可叠代對象)
我們已經知道,可以直接作用於for
循環的數據類型有以下幾種:一類是集合數據類型,如list
、tuple
、dict
、set
、str
等;一類是generator
,包括生成器和帶yield
的generator function。這些可以直接作用於for
循環的對象統稱為可叠代對象:Iterable
。可以使用isinstance()
判斷一個對象是否是Iterable
對象。
from collections import Iterable print(isinstance([],Iterable),isinstance({},Iterable),isinstance(set,Iterable),isinstance("abc",Iterable))#執行結果True True False True
然而,生成器不但能夠作用於for循環,還具有__next__()方法,像這種可以被next()
函數調用並不斷返回下一個值的對象稱為叠代器:Iterator
。可以使用isinstance()
判斷一個對象是否是Iterator
對象。
1 from collections import Iterable,Iterator 2 print(isinstance([],Iterator),isinstance({},Iterator),isinstance(set,Iterator),isinstance("abc",Iterator),isinstance((i*2 for i in range(10)),Iterator))#執行結果False False False False True
然而,我們可以通過iter()方法把可叠代對象轉換為叠代器
1 from collections import Iterable,Iterator 2 print(isinstance(iter([]),Iterator))
那為什麽像list,字典都不是叠代器呢?
這是因為Python的Iterator
對象表示的是一個數據流,Iterator對象可以被next()
函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration
錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()
函數實現按需計算下一個數據,所以Iterator
的計算是惰性的,只有在需要返回下一個數據時它才會計算。
Iterator
甚至可以表示一個無限大的數據流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。
總結:
1、凡是可作用於for
循環的對象都是Iterable
類型;
2、凡是可作用於next()
函數的對象都是Iterator
類型,它們表示一個惰性計算的序列;
3、集合數據類型如list
、dict
、st
r
等是Iterable
但不是Iterator
,不過可以通過iter()
函數獲得一個Iterator
對象。
4、Python的for
循環本質上就是通過不斷調用next()
函數實現的,例如:
1 for x in [1, 2, 3, 4, 5]: 2 pass
其實際上的實現步驟為:
1 # 首先獲得Iterator對象: 2 it = iter([1, 2, 3, 4, 5]) 3 # 循環: 4 while True: 5 try: 6 # 獲得下一個值: 7 x = next(it) 8 except StopIteration: 9 # 遇到StopIteration就退出循環 10 break
Python之叠代器