Python語言特性-迭代器和生成器

迭代器

定義:對於list、string、tuple、dict等這些容器對象,使用for循環遍歷是很方便的。在後臺for語句對容器對象調用iter()函數。iter()是python內置函數。
iter()函數會返回一個定義了next()方法的迭代器對象,它在容器中逐個訪問容器內的元素。next()也是python內置函數。在沒有後續元素時,next()會拋出一個StopIteration異常,通知for語句循環結束。
迭代器是用來幫助我們記錄每次迭代訪問到的位置,當我們對迭代器使用next()函數的時候,迭代器會向我們返回它所記錄位置的下一個位置的數據。實際上,在使用next()函數的時候,調用的就是迭代器對象的_next_方法(Python3中是對象的_next_方法,Python2中是對象的next()方法)。所以,我們要想構造一個迭代器,就要實現它的_next_方法。但這還不夠,python要求迭代器本身也是可迭代的,所以我們還要爲迭代器實現_iter_方法,而_iter_方法要返回一個迭代器,迭代器自身正是一個迭代器,所以迭代器的_iter_方法返回自身self即可。

其中迭代器協議是指:對象需要提供next()方法,它要麼返回迭代中的下一項,要麼就引起一個異常,終止迭代。
可迭代對象實現了迭代器協議對象。像list, dict, tuple都是可迭代對象,可以通過內建函數iter() ,把這些都變成iterable(可迭代對象)。
for 循環的本質就是先通過iter()函數獲取可迭代對象Iterable的迭代器,然後對回去到的迭代器不斷調用next()方法來獲取下一個值並將其賦值給item,當遇到StopIteration的異常後循環結束。

Python中一個實現了_iter_方法和_next_方法的類對象,就是迭代器。

下面我們看一個計算斐波那契數列的例子:


class Fib(object):
    def __init__(self, max):
        super(Fib, self).__init__()
        self.max = max
	
    def __iter__(self):
        self.a = 0
        self.b = 1
        return self
	def __next__(self):
		fib = self.a
		if fib > self.max:
			raise StopIteration
		self.a, self.b = self.b, self.a + self.b
		return fib

# 定義一個mian函數,循環遍歷
def main():
	fib = Fib(10000)
	for i in fib:
		print(i)
	
if __name__ == '__main__':
    main()

解釋說明
在本類的實現中,定義了一個_iter_(self)方法,這個方法是在for循環遍歷時被iter()調用,返回一個迭代器。因爲在遍歷的時候,是直接調用的python內置函數iter(),由iter()通過調用_iter_(self)獲得對象的迭代器。有了迭代器,就可以逐個遍歷元素了。而逐個遍歷的時候,也是使用內置的next()函數通過調用對象_next_(self)方法對迭代器對象進行遍歷。所以要實現_iter_(self)和_next_(self)這兩個方法。

總的來說就是在循環遍歷自定義容器對象時,會使用python內置函數iter()調用遍歷對象__iter__(self)獲得一個迭代器,之後再循環對這個迭代器使用next()調用迭代器對象的__next__(self).
iter(self)只會被調用一次,而__next__(self)會被調用N次,直到出現異常。

生成器

生成器是一類特殊的迭代器,在循環遍歷的時候會在需要的時候產生結果,即延遲操作。 生成器值遍歷一次。

可以大概把生成器分爲兩類:
第一類:
生成器函數:即使用def定義函數,使用yield語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,一遍下次從它離開的地方繼續執行。
下面我們繼續用斐波那契數列來舉例:


def Fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return ' 請添加數據'
# 調用方法,生成出10個數來
f=Fib(10)

# 使用一個循環捕獲最後return 返回的值,保存在異常StopIteration的value中
while  True:
    try:
    	x=next(f)
        print("f:",x)
    except StopIteration as e:
        print("生成器最後的返回值是:",e.value)
        

第二類:
生成器表達式:類似於列表推導式,把[]換成()就可以了。 但是生成器表達式是按需產生一個生成器結果對象,想要拿到每一個元素,就需要循環遍歷一次。
如下:

# 一個列表
xiaoke=[2,3,4,5]
# 生成器generator,類似於list,但是是把[]改爲()
gen=(a for a  in xiaoke)
for  i  in gen:
    print(i)

使用生成器的主要目的就是爲了提高效率。用生成器表達式取代列表推導式可以同時節省CPU的使用和內存的佔用。

 # python內置的一些函數,可以識別這是生成器表達式,外面有一對小括號,就是生成器
 ret1=sum(a for a in range(10))
 print(ret1) 
  # 列表推導式 
 ret2=sum([a for a in range(10)])
  print(ret2)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章