本文以例項詳解了python的迭代器與生成器,具體如下所示:
1. 迭代器概述:
迭代器是訪問集合元素的一種方式。迭代器物件從集合的第乙個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退,不過這也沒什麼,因為人們很少在迭代途中往後退。
1.1 使用迭代器的優點
對於原生支援隨機訪問的資料結構(如tuple、list),迭代器和經典for迴圈的索引訪問相比並無優勢,反而丟失了索引值(可以使用內建函式enumerate()找回這個索引值)。但對於無法隨機訪問的資料結構(比如set)而言,迭代器是唯一的訪問元素的方式。
另外,迭代器的一大優點是不要求事先準備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷毀。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個g的檔案,或是斐波那契數列等等。
迭代器更大的功勞是提供了乙個統一的訪問集合的介面,只要定義了__iter__()方法物件,就可以使用迭代器訪問。
迭代器有兩個基本的方法
__iter__方法:返回迭代器物件本身
下面用生成斐波那契數列為例子,說明為何用迭代器
示例**1
def fab(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a + b
n = n + 1
直接在函式fab(max)中用print列印會導致函式的可復用性變差,因為fab返回none。其他函式無法獲得fab函式返回的數列。
示例**2
def fab(max):
l =
n, a, b = 0, 0, 1
while n < max:
a, b = b, a + b
n = n + 1
return l
**2滿足了可復用性的需求,但是占用了記憶體空間,最好不要。
示例**3
對比:
for i in range(1000): pass
for i in xrange(1000): pass
前乙個返回1000個元素的列表,而後乙個在每次迭代中返回乙個元素,因此可以使用迭代器來解決復用可佔空間的問題
class fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise stopiteration()
執行
>>> for key in fabs(5):
print key
fabs 類通過 next() 不斷返回數列的下乙個數,記憶體占用始終為常數
1.2 使用迭代器
使用內建的工廠函式iter(iterable)可以獲取迭代器物件:
>>> lst = range(5)
>>> it = iter(lst)
>>> it
>>> it.next()
>>> it.next()
>>> it.next()
python處理迭代器越界是丟擲stopiteration異常
>>> it.next()
>>> it.next
>>> it.next()
traceback (most recent call last):
file "", line 1, in it.next()
stopiteration
了解了stopiteration,可以使用迭代器進行遍歷了
lst = range(5)
it = iter(lst)
try:
while true:
val = it.next()
print val
except stopiteration:
pass
事實上,因為迭代器如此普遍,python專門為for關鍵字做了迭代器的語法糖。在for迴圈中,python將自動呼叫工廠函式iter()獲得迭代器,自動呼叫next()獲取元素,還完成了檢查stopiteration異常的工作。如下
>>> a = (1, 2, 3, 4)
>>> for key in a:
print key
首先python對關鍵字in後的物件呼叫iter函式迭代器,然後呼叫迭代器的next方法獲得元素,直到丟擲stopiteration異常。
1.3 定義迭代器
下面乙個例子——斐波那契數列
# -*- coding: cp936 -*-
class fabs(object):
def __init__(self,max):
self.max = max
self.n, self.a, self.b = 0, 0, 1 #特別指出:第0項是0,第1項是第乙個1.整個數列從1開始
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise stopiteration()
print fabs(5)
for key in fabs(5):
print key
結果
<__main__.fabs object at 0x01a63090>
2. 迭代器
帶有 yield 的函式在 python 中被稱之為 generator(生成器),幾個例子說明下(還是用生成斐波那契數列說明)
可以看出**3遠沒有**1簡潔,生成器(yield)既可以保持**1的簡潔性,又可以保持**3的效果
示例**4
def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n = 1
執行
>>> for n in fab(5):簡單地講,yield 的作用就是把乙個函式變成乙個 generator,帶有 yield 的函式不再是乙個普通函式,python 直譯器會將其視為乙個 generator,呼叫 fab(5) 不會執行 fab 函式,而是返回乙個 iterable 物件!在 for 迴圈執行時,每次迴圈都會執行 fab 函式內部的**,執行到 yield b 時,fab 函式就返回乙個迭代值,下次迭代時,**從 yield b 的下一條語句繼續執行,而函式的本地變數看起來和上次中斷執行前是完全一樣的,於是函式繼續執行,直到再次遇到 yield。看起來就好像乙個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。print n
也可以手動呼叫 fab(5) 的 next() 方法(因為 fab(5) 是乙個 generator 物件,該物件具有 next() 方法),這樣我們就可以更清楚地看到 fab 的執行流程:
>>> f = fab(3)
>>> f.next()
>>> f.next()
>>> f.next()
>>> f.next()
traceback (most recent call last):
file "", line 1, in f.next()
stopiteration
return作用
在乙個生成器中,如果沒有return,則預設執行到函式完畢;如果遇到return,如果在執行過程中 return,則直接丟擲 stopiteration 終止迭代。例如
>>> s = fab(5)
>>> s.next()
>>> s.next()
traceback (most recent call last):
file "", line 1, in s.next()
stopiteration
示例**5 檔案讀取
def read_file(fpath):
block_size = 1024
with open(fpath, 'rb') as f:
while true:
block = f.read(block_size)
if block:
yield block
else:
return
如果直接對檔案物件呼叫 read() 方法,會導致不可**的記憶體占用。好的方法是利用固定長度的緩衝區來不斷讀取檔案內容。通過 yield,我們不再需要編寫讀檔案的迭代類,就可以輕鬆實現檔案讀取。 Python生成器與迭代器
生成器只有在用的時候會出現在記憶體中,對比列表全部存在記憶體中,減少了記憶體占用 next 函式 依次取生成器的值 s x 2 for x in range 1000 中括號是列表解析,小括號表示生成一系列值,就是生成器 s at 0x7fa20aa8b048 print next s 用next ...
python 迭代器與生成器
迭代器和生成器 print 1 in 1,2,3 print 1 not in 1,2,3 print 4 in print 4 not in 1,2,3 print x not in dlkjfxfei 可迭代物件 iterable 可以被next 函式呼叫並不斷返回下乙個值 知道沒有資料時丟擲s...
Python 迭代器與生成器
一 迭代器 理解迭代器需要搞清楚容器 container 迭代器協議 可迭代物件 iterable 迭代器 iterator 生成器 generator 1 容器 container 容器是一種把多個元素組織在一起的資料結構,容器中的元素可以逐個地迭代獲取,可以用in,not in關鍵字判斷元素是否...