第14章 可叠代的對象、叠代器和生成器
阿新 • • 發佈:2018-09-05
python3.4 找到 range 處理 數據庫 優化 重新 next pytho
#第14章 可叠代的對象、叠代器和生成器 # 叠代是數據處理的基石。掃描內存中放不下的數據集時,我們要找到一種惰性獲取數據項的方式,即按需一次獲取一個數據項。這就是叠代器模式(Iterator pattern)。 # 所有生成器都是叠代器,因為生成器完全實現了叠代器接口。 # 叠代器用於從集合中取出元素;而生成器用於“憑空”生成元素。 # 14.1 Sentence類第1版:單詞序列 # 示例 14-1 sentence.py:把句子劃分為單詞序列 import re import reprlib RE_WORD=re.compile(‘\w+‘) class Sentence: def__init__(self,text): self.text=text self.words=RE_WORD.findall(text) def __getitem__(self, index): return self.words[index] def __len__(self):# 為了完善序列協議,我們實現了__len__方法;不過,為了讓對象可以叠代,沒必要實現這個方法。 return len(self.words) def __repr__(self):# reprlib.repr 這個實用函數用於生成大型數據結構的簡略字符串表示形式。return ‘Sentence(%s)‘%reprlib.repr(self.text) # 示例 14-2 測試 Sentence 實例能否叠代 s=Sentence(‘"The time has come,"the Walrus said,‘) print(s) for word in s: print(word) print(list(s)) print(s[0],s[5],s[-1]) # 任何 Python 序列都可叠代的原因是,它們都實現了 __getitem__ 方法。 # 從Python 3.4開始,檢查對象x能否叠代,最準確的方法是:調用iter(x)函數,如果不可叠代,再處理TypeError異常。# 14.2 可叠代的對象與叠代器的對比 # 標準的叠代器接口有兩個方法。 # __next__返回下一個可用的元素,如果沒有元素了,拋出 StopIteration異常。 # __iter__返回 self,以便在應該使用可叠代對象的地方使用叠代器,例如在for循環中。 # 叠代器叠代器是這樣的對象:實現了無參數的 __next__ 方法,返回序列中的下一個元素;如果沒有元素了,那麽拋出 StopIteration 異常。 # 14.3 Sentence類第2版:典型的叠代器 # 例14-4 sentence_iter.py:使用叠代器模式實現Sentence類 import re import reprlib RE_WORD=re.compile(‘\w+‘) class Sentence: def __init__(self,text): self.text=text self.words=RE_WORD.findall(text) def __repr__(self): return ‘Sentence(%s)‘%reprlib.repr(self.text) def __iter__(self): return SentenceIterator(self.words) class SentenceIterator: def __init__(self,words): self.words=words self.index=0 def __next__(self): try: word=self.words[self.index] except IndexError: raise StopIteration() self.index+=1 return word def __iter__(self): return self # 叠代器模式可用來: # 訪問一個聚合對象的內容而無需暴露它的內部 # 表示支持對聚合對象的多種遍歷 # 為遍歷不同的聚合結構提供一個統一的接口(即支持多態叠代) # 14.4 Sentence類第3版:生成器函數 import re import reprlib RE_WORD=re.compile(‘\w+‘) class Sentence: def __init__(self,text): self.text=text self.words=RE_WORD.findall(text) def __repr__(self): return ‘Sentence(%s)‘.reprlib.repr(self.text) def __iter__(self): for word in self.words: yield word return # 這個return語句不是必要的;這個函數可以直接“落空”,自動返回。 # 不管有沒有return語句,生成器函數都不會拋出StopIteration異常,而是在生成完全部值之後會直接退出。 # 生成器函數的工作原理 # 只要 Python 函數的定義體中有 yield 關鍵字,該函數就是生成器函數。 # 調用生成器函數時,會返回一個生成器對象。也就是說,生成器函數是生成器工廠。 # 只要 Python 函數中包含關鍵字 yield,該函數就是生成器函數。 # 14.5 Sentence類第4版:惰性實現 # 示例 14-7 sentence_gen2.py: 在生成器函數中調用 re.finditer生成器函數,實現 Sentence 類 import re import reprlib RE_WORD=re.compile(‘\w+‘) class Sentence: def __init__(self,text): self.text=text def __repr__(self): return ‘Sentence(%s)‘%reprlib.repr(self.text) def __iter__(self): for match in RE_WORD.finditer(self.text) yield match.group() # 14.6 Sentence類第5版:生成器表達式 # 生成器表達式可以理解為列表推導的惰性版本:不會迫切地構建列表,而是返回一個生成器,按需惰性生成元素。 # 示例 14-9 sentence_genexp.py:使用生成器表達式實現 Sentence類 import re import reprlib RE_WORD=re.compile(‘\w+‘) class Sentence: def __init__(self,text): self.text=text def __repr__(self): return ‘Sentence(%)‘%.reprlib.repr(self.text) def __iter__(self): return (match.group() for match in RE_WORD.finditer(self.text)) # 生成器表達式是語法糖:完全可以替換成生成器函數,不過有時使用生成器表達式更便利。下一節說明生成器表達式的用途。 # 14.7 何時使用生成器表達式 # 生成器表達式是創建生成器的簡潔句法,這樣無需先定義函數再調用。 # 不過,生成器函數靈活得多,可以使用多個語句實現復雜的邏輯,也可以作為協程使用 # 14.8 另一個示例:等差數列生成器 # 典型的叠代器模式作用很簡單——遍歷數據結構。 # 示例 14-11 ArithmeticProgression 類 class ArithmeticProgression: def __init__(self,begin,step,end=None): self.begin=begin self.step=step self.end=end def __iter__(self): result=type(self.begin+self.step)(self.begin) forever=self.end is None index=0 while forever or result <self.end: yield result index +=1 result=self.begin+self.step*index # 示例 14-10 演示 ArithmeticProgression 類的用法 ap=ArithmeticProgression(0,1,3) print(list(ap)) ap=ArithmeticProgression(1,.5,3) print(list(ap)) ap=ArithmeticProgression(0,1/3,1) print(list(ap)) from fractions import Fraction ap=ArithmeticProgression(0,Fraction(1,3),1) print(list(ap)) from decimal import Decimal ap=ArithmeticProgression(0,Decimal(‘.1‘),.3) print(list(ap)) # 使用itertools模塊生成等差數列 # Python3.4中的itertools模塊提供了19個生成器函數,結合起來使用能實現很多有趣的用法。 import itertools gen=itertools.count(1,.5) print(next(gen),next(gen),next(gen)) # 不過,itertools.takewhile 函數則不同,它會生成一個使用另一個生成器的生成器, # 在指定的條件計算結果為 False 時停止。因此,可以把這兩個函數結合在一起使用。 gen=itertools.takewhile(lambda n:n<3,itertools.count(1,.5)) print(list(gen)) # 示例 14-13 aritprog_v3.py:與前面的aritprog_gen函數作用相同 import itertools def aritprog_gen(begin,step,end=None): first=type(begin+step)(begin) ap_gen=itertools.count(first,step) if end is not None: ap_gen=itertools.takewhile(lambda n:n<end,ap_gen) return ap_gen # 示例 14-13 想表達的觀點是,實現生成器時要知道標準庫中有什麽可用,否則很可能會重新發明輪子。 # 14.9 標準庫中的生成器函數 # 示例14-15演示itertools.accumulate生成器函數 sample=[5,4,2,8,7,6,3,0,9,1] import itertools print(list(itertools.accumulate(sample)))#計算總和。 print(list(itertools.accumulate(sample,min)))#計算最小值。 print(list(itertools.accumulate(sample,max)))#計算最大值。 import operator print(list(itertools.accumulate(sample,operator.mul)))#計算乘積。 print(list(itertools.accumulate(range(1,11),operator.mul)))#從1!到10!,計算各個數的階乘。 # 示例 14-17 演示用於合並的生成器函數 print(list(itertools.chain(‘ABC‘,range(2)))) print(list(itertools.chain(enumerate(‘ABC‘)))) print(list(itertools.chain.from_iterable(enumerate(‘ABC‘)))) print(list(zip(‘ABC‘,range(5)))) print(list(zip(‘ABC‘,range(5),[10,20,30,40]))) print(list(itertools.zip_longest(‘ABC‘,range(5)))) print(list(itertools.zip_longest(‘ABC‘,range(5),fillvalue=‘?‘))) #14.10 Python3.3中新出現的句法:yield from def chain(*iterables): for i in iterables: yield from i print(list(chain(‘ABC‘,tuple(range(3))))) # 除了代替循環之外,yield from還會創建通道,把內層生成器直接與外層生成器的客戶端聯系起來。 # 14.11 可叠代的歸約函數 # 表 14-6 中的函數都接受一個可叠代的對象,然後返回單個結果。這些函數叫“歸約”函數、“合攏”函數或“累加”函數。 # 此外,對all和any數來說,有一項重要的優化措施是reduce函數做不到的: # 這兩個函數會短路(即一旦確定了結果就立即停止使用叠代器)。 # all(it)it 中的所有元素都為真值時返回True,否則返回False;all([])返回True # any(it)只要it中有元素為真值就返回True,否則返回False;any([])返回False # 14.12 深入分析iter函數 from random import randint def d6(): return randint(1,6) d6_iter=iter(d6,1) # 第二個值是哨符,這是個標記值,當可調用的對象返回這個值時, # 觸發叠代器拋出 StopIteration 異常,而不產出哨符。 print(d6_iter) for roll in d6_iter: print(roll) # 14.13 案例分析:在數據庫轉換工具中使用生成器 # 14.14 把生成器當成協程 # 14.15 本章小結 # 14.16 延伸閱讀 def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b
第14章 可叠代的對象、叠代器和生成器