Python迭代器Iterator和生成器generator
容器(container)
容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,可以用in
, not in
關鍵字判斷元素是否包含在容器中。通常這類資料結構把所有的元素儲存在記憶體中(也有一些特例,並不是所有的元素都放在記憶體,比如迭代器和生成器物件)
可迭代物件(iterable)
很多容器都是可迭代物件,此外還有更多的物件同樣也是可迭代物件,比如處於開啟狀態的files,sockets等等。但凡是可以返回一個迭代器的物件都可稱之為可迭代物件,例如:
>>> x = [1, 2, 3] >>> y = iter(x) >>> z = iter(x) >>> next(y) 1 >>> next(y) 2 >>> next(z) 1 >>> type(x) <class 'list'> >>> type(y) <class 'list_iterator'>
這裡x
是一個可迭代物件,可迭代物件和容器一樣是一種通俗的叫法,並不是指某種具體的資料型別,list是可迭代物件,dict是可迭代物件,set也是可迭代物件。y
和z
是兩個獨立的迭代器,迭代器內部持有一個狀態,該狀態用於記錄當前迭代所在的位置,以方便下次迭代的時候獲取正確的元素。迭代器有一種具體的迭代器型別,比如list_iterator
,set_iterator
。可迭代物件實現了__iter__
方法,該方法返回一個迭代器物件。
迭代器(iterator)
什麼是迭代器
迭代器是訪問可迭代物件的工具
迭代器是指用iter(obj) 函式返回的物件(例項)
迭代器可以用next(it) 函式獲取可迭代物件的資料任何實現了
__iter__
和__next__()
(python2中實現next()
)方法的物件都是迭代器,__iter__
返回迭代器自身,__next__
返回容器中的下一個值
迭代器函式iter()和next()
iter(iterable) : 從可迭代物件中返回一個迭代器,iterable 必須是能提供一個迭代器的物件
next(iterator) : 從迭代器iterator中獲取下一個記錄,如果無法獲取下一條記錄,則觸發StopIteration異常說明:
迭代器只能向前取值,不會後退
用iter函式可以返回一個可迭代物件的迭代器
作用:
迭代器物件能用next函式獲取下一個元素.
為了更直觀地感受迭代器內部的執行過程,我們自定義一個迭代器,以斐波那契數列為例:
class Fib:
def __init__(self):
self.prev = 0
self.curr = 1
def __iter__(self):
return self
def __next__(self):
value = self.curr
self.curr += self.prev
self.prev = value
return value
>>> f = Fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Fib既是一個可迭代物件(因為它實現了__iter__
方法),又是一個迭代器(因為實現了__next__
方法)。例項變數prev
和curr
使用者維護迭代器內部的狀態。每次呼叫next()
方法的時候做兩件事:
- 為下一次呼叫
next()
方法修改狀態 - 為當前這次呼叫生成返回結果
生成器(generator)
生成器其實是一種特殊的迭代器,不過這種迭代器更加優雅。它不需要再像上面的類一樣寫__iter__()
和__next__()
方法了,只需要一個yiled
關鍵字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一種懶載入的模式生成值
用生成器來實現斐波那契數列的例子如下:
def fib():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, curr + prev
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib
就是一個普通的python函式,它特殊的地方在於函式體中沒有return
關鍵字,函式的返回值是一個生成器物件。當執行f=fib()
返回的是一個生成器物件,此時函式體中的程式碼並不會執行,只有顯示或隱示地呼叫next的時候才會真正執行裡面的程式碼。
生成器在Python中是一個非常強大的程式設計結構,可以用更少地中間變數寫流式程式碼,此外,相比其它容器物件它更能節省記憶體和CPU,當然它可以用更少的程式碼來實現相似的功能
什麼是生成器:
生成器是能夠動態提供資料的物件,生成器物件也是可迭代物件(例項)
生成器有兩種:
1. 生成器函式
2. 生成器表示式
生成器函式的定義
含有yield語句的函式是生成器函式,此函式被呼叫將返回一個生成器物件
yield 翻譯為(產生或生成)
yield 語句
語法:
yield 表示式
說明:
yield 用於 def 函式中,目的是將此函式作用生成器函式使用
yield 用來生成資料,供迭代器的next(it) 函式使用
生成器函式說明:
生成器函式的呼叫將返回一個生成器物件,生成器物件是一個可迭代物件
在生成器函式呼叫return 會觸發一個StopIteration異常
因此在程式碼中類似如下程式碼可以重構優化 :
def something(): result = [] for ... in ...: result.append(x) return result
可以優化為:
def iter_something(): for ... in ...: yield x
下面方法較上面方法更節省CPU和記憶體
生成器表示式:
語法:
(表示式 for 變數 in 可迭代物件 [if 真值表達式 ])
說明:
if 子句可以省略
作用:
用推導式的形式建立一個新的生成器
迭代工具函式
迭代工具函式的作用是生成一個個性化的可迭代物件
函式:
zip(iter1[, iter2[, ...]]) 返回一個zip物件,此物件用於生成元組,此元組的個數由最小的可迭代物件決定
enumerate(iterable[, start]) 生成帶索引的列舉物件,返回迭代型別為索引-值對(index-value對),預設索引從零開始,也可以用start指定