Python中的可迭代的對象、迭代器和生成器

導語:本文章記錄了本人在學習Python基礎之控制流程篇的重點知識及我的心得,打算入門Python的朋友們能夠來一塊兒學習並交流。

本文重點:python

一、掌握可迭代的對象的定義;
二、掌握可迭代對象、迭代器與生成器之間的關係和異同;
三、熟悉標準庫中生成器。

1、可迭代的對象

可迭代的對象:使用iter內置函數能夠獲取迭代器的對象。若是對象實現了能返回迭代器的__iter__方法,那麼對象就是可迭代的。若是沒有實現__iter__而實現了__getitem__方法,而且其參數是從零開始的索引,這種對象如序列也是可迭代的。
向後兼容:之因此任何Python序列可迭代是爲了向後兼容。ssh

當解釋器須要迭代對象時,會自動調用iter(x):函數

  • 若對象實現了__iter__方法,獲取一個迭代器;
  • 若對象沒實現__iter__方法,但實現了__getitem__方法,Python會建立一個迭代器,嘗試從索引0開始獲取元素;
  • 若嘗試失敗,Python拋出TypeError。

標準的序列都實現了__iter__方法,這是鴨子類型的極端形式。
在白鵝類型中,只要對象實現了__iter__方法,那麼它就是可迭代的對象。學習

注意:
(1)只有實現了__iter__方法的對象能經過子類測試issubclass(Object,abc.Iterator)
(2)檢查對象可否迭代最準確的方法是調用iter(x)函數,若是不可迭代再處理TypeError。由於iter(x)會考慮到實現__getitem__方法的部分可迭代對象。測試

2、迭代器

一、迭代器介紹

迭代器:用於從集合中取出元素的對象。
迭代器的功能:用於支持下列操做spa

  • for循環
  • 構建和擴展集合類型
  • 逐行遍歷文本文件
  • 列表推導、字典推導和集合推導
  • 元組拆包
  • 調用函數時,使用 * 拆包實參

迭代器的接口協議code

  • __next__,返回下一個可用的元素。當沒有元素時拋出StopIteration異常。
  • __iter__,返回self,即迭代器自己。

圖片描述
迭代器特色:orm

  • 可迭代。因爲Python中的迭代器實現了__iter__方法,所以也能夠迭代。
  • 易耗損。迭代器通過一次逐次取值的循環後便耗盡了。若想再次迭代須重建迭代器。

迭代器檢查方式:調用isinstance(object,abc.Iterator)。
檢查原理:歸結於Iterator.__subclasshook__方法。不管對象所屬的類是Iterator的真實子類仍是虛擬子類,都可以檢查。協程

二、迭代器和可迭代對象之辨析:

  • 聯繫:Python從可迭代的對象中獲取迭代器
  • 區別:可迭代的對象不是迭代器

三、迭代器模式

迭代器模式:按需一次獲取一個數據項。
掃描內存中放不下的數據集時,咱們要找到一種惰性獲取數據項的方式,即按需一次獲取一個數據項。這就是迭代器模式(Iterator pattern) 。
迭代器模式的用途:對象

  • 訪問一個聚合對象的內容而無需暴露它的內部表示
  • 支持對聚合對象的多種遍歷
  • 爲遍歷不一樣的聚合結構提供一個統一的接口(即支持多態迭代)

四、迭代器模式實例

下面構造一個能夠處理文本匹配並迭代的實例:

import reprlib
import re

reword=re.compile('\w+')
#初版:迭代器模式
class Sentence:
    def __init__(self,text):
        self.text=text
        self.words=reword.findall(text)
    def __repr__(self):
        return "Sentence({})".format(reprlib.repr(self.text))
    def __iter__(self):
        return SentenceIterator(self.words)
class SentenceIterator:
    def __init__(self,text):
        self.words=text
        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
title=Sentence('We have a dream!')
print(title)
for i in title:
    print(i)
輸出:
Sentence('We have a dream!')
We
have
a
dream

注意:
(1)不要把迭代器接口應用到可迭代對象上,這是常見的反模式
(2)可迭代對象必須實現__iter__方法,但不能實現__next__方法

3、生成器

一、生成器相關概念介紹

生成器:用於按需生成元素的對象。在Python社區中大多數時候都把迭代器和生成器視做同一律念。

生成器函數:擁有yield關鍵字的Python函數。
生成器表達式:製造生成器的工廠,支持惰性產值。
生成器工廠函數:返回生成器的函數,定義體中能夠沒有yield關鍵字。

生成器函數與生成器表達式優勢比較:

  • 生成器函數:使用重複使用的情景,也能夠做爲協程使用。
  • 生成器表達式:代碼簡潔易讀。

Tips:生成器表達式做爲單參數傳入時無須寫一對括號,而多參數時須將小括號加上。

二、生成器函數工做原理

實例1:經過一個問候同窗的代碼來了解生成器函數是如何工做的

def gen():
    print("start")
    yield "Jack"
    print("continue")
    yield "Dennis"
    print("end")
for i in gen():
    print("Hello ",i)
輸出:
start
Hello  Jack
continue
Hello  Dennis
end

原理分析:不難發現,for循環中操做的對象是生成器中的yield生成的值。緣由在於,生成器是迭代器,會生成傳給yield關鍵字的表達式的值。
注意:無論有沒有return語句,生成器函數都不會拋出StopIteration異常,而是在生成所有值以後直接退出。

實例2:生成器函數改進版

import reprlib
import re

reword=re.compile('\w+')
#第二版:生成器函數
class Sentence:
    def __init__(self,text):
        self.text=text
        self.words=reword.findall(text)
    def __repr__(self):
        return "Sentence({})".format(reprlib.repr(self.text))
    def __iter__(self):
        for i in self.words:
            yield i
        return
title=Sentence('We have a dream!')
print(title)
for i in title:
    print(i)

三、惰性產值:生成器表達式模式改進版

import reprlib
import re

reword=re.compile('\w+')
#第三版:生成器表達式
class Sentence:
    def __init__(self,text):
        self.text=text
    def __repr__(self):
        return "Sentence({})".format(reprlib.repr(self.text))
    def __iter__(self):
        return (match.group() for match in reword.finditer(self.text))
title=Sentence('We have a dream!')
print(title)
for i in title:
    print(i)

Tips:re.finditer函數是re.findall函數的惰性版本,返回的不是列表而是一個生成器,按需惰性生成元素。

4、標準庫中有用的生成器

一、五大類生成器

  • 用於過濾的生成器函數: itertools.takewhile/compress/dropwhile/filter/filterfalse/islice/
  • 用於映射的生成器函數: 內置的 enumerate/map itertools.accumulate/starmap
  • 用於合併的生成器函數:itertools.chain/from_iterable/product/zip_longest/ 內置的 zip
  • 從一個元素產生多個值,擴展輸入的可迭代對象: itertools.combinations/combinations_with_replacement/count/cycle/permutations/repeat
  • 產出輸入可迭代對象的所有元素,以某種方式排列:itertools.groupby/tee/ 內置的 reversed

5、其它

一、歸約函數:接受可迭代對象並返回單個結果的函數。
圖片描述這裏的all和any函數會短路,即一旦得出結果立刻中止迭代。

相關文章
相關標籤/搜索