Python叠代器生成器
在學習python數據結構的過程中,可叠代對象,叠代器,生成器這些概念參雜在一起,難免讓初學者一頭霧水,今天就來捋捋這些概覽。
可叠代對象(iterable)
什麽是可叠代對象,通俗的講就是可以直接通過for循環遍歷的對象就可稱為可叠代對象Iterable,可以使用isinstance()判斷一個對象是否是Iterable對象:
>>>from collections import Iterable
>>>isinstance([], Iterable)
True
>>>isinstance({}, Iterable)True
>>>isinstance(‘123‘, Iterable)
True
>>>isinstance(123, Iterable)
False
可叠代對象並不指某種具體的數據類型,list, dict, set, str都是叠代對象,再比如打開狀態的files,sockets也是可叠代對象,可叠代對象是指代對象的一種屬性,代表該對象是可叠代的。可叠代對象實現了__iter__方法,該方法返回一個叠代器對象。
叠代器(iterator)
任何實現了__iter__和__next__方法的對象都是叠代器(python2是實現__iter__和next方法),__iter__返回叠代器自身,__next__返回容器中的下一個值,如果容器中沒有更多元素了,則拋出StopIteration異常。可以使用isinstance()判斷一個對象是否是Iterator對象:
>>>from collections import Iterator
>>>isinstance([], Iterator)
False
>>>isinstance({}, Iterator)
False
>>>isinstance(‘123‘, Iterator)
False
>>>isinstance((x for x in range(10)), Iterator)
True
其中(x for x in range(10))是生成器表達式,它返回的是一個生成器對象,不同於列表生成式[x for x in range(10)]返回一個list對象。生成器對象都是叠代器對象,但list, dict, str雖然是可叠代對象,但不是叠代器對象,可以使用iter()將list, dict, str等可叠代對象變成叠代器對象。
>>>isinstance(iter([]), Iterator)
True
>>>isinstance(iter(‘123‘), Iterator)
True
python的叠代器對象表示一個數據流,可以將這個數據流看作一個有序序列,但我們並不知道序列的長度,只能不斷通過調用next()函數實現按需計算下一個數據,因此叠代器的計算是惰性的,只有在需要返回下一個數據時它才計算,叠代器的這種特性可以大大減少內存的開銷,叠代器對象甚至可以表示一個無限大的數據流,而讓list, dict或者str存儲一個無限大的數據流是不可能的。
下面我們通過叠代器來實現斐波那契數列:
from collections import Iterable
from collections import Iterator
class Fib:
def __init__(self, max):
self.n, self.max = 0, max
self.a, self.b = 0, 1
def __iter__(self):
return self
def __next__(self):
if self.n < self.max:
self.n += 1
self.a, self.b = self.b, self.a + self.b
return self.a
else:
raise StopIteration
if __name__ == ‘__main__‘:
fib = Fib(10)
print(isinstance(fib, Iterable)) # True
print(isinstance(fib, Iterator)) # True
print([e for e in fib]) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Fib既是一個可叠代對象(因為它實現了__iter__方法),又是一個叠代器(因為實現了__next__方法)。實例變量a和b用於維護叠代器內部的狀態。每次調用next()方法的時候做兩件事:
為下一次調用next()方法修改狀態,為當前這次調用生成返回結果。
叠代器就像一個懶加載的工廠,等到有人需要的時候才給它生成值返回,沒調用的時候就處於休眠狀態等待下一次調用。
生成器(generator)
生成器是一種特殊的叠代器,不過這種叠代器更加優雅。它不需要再像上面的類一樣寫__iter__()和__next__()方法了,只需要一個yiled關鍵字。
用生成器來實現斐波那契數列的例子是:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
n = n + 1
a, b = b, b + a
yield a
f = fib(10)
print(f) # <generator object fib at 0x10d8cf888>
print([e for e in f]) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib函數中的yield關鍵字,將該函數變成了一個生成器,當執行f=fib(10)返回的是一個生成器對象,此時函數中的代碼並不會執行,只有顯示或隱示地調用next的時候才會真正執行裏面的代碼,在每次調用next()方法時,遇到yield語句返回值並中斷,再次執行時從上次返回的yield語句處繼續執行。
生成器是python非常強大的特性,相比其他容器對象它更加節省內存,同時使用更少的代碼,使你的代碼更加的優雅,凡事以下結構都可以通過生成器重構:
def fun():
result = []
for ... in ...:
result.append(x)
return result
def fun_gen():
for ... in ...:
yield x
總結
- 可叠代對象實現了__iter__方法,該方法返回一個叠代器對象。
- 叠代器持有一個內部狀態的字段,用於記錄下次叠代返回值,它實現了__next__和__iter__方法,叠代器不會一次性把所有元素加載到內存,而是需要的時候才生成返回結果。
- 生成器是一種特殊的叠代器,它的返回值不是通過return而是用yield。
Python叠代器生成器