天天看點

Python 進階_疊代器 & 清單解析目錄疊代器清單解析清單解析和疊代器

<a href="#%E7%9B%AE%E5%BD%95">目錄</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8">疊代器</a>

<a href="#iter-%E5%86%85%E5%BB%BA%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0">iter 内建的疊代器生成函數</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%9C%A8-for-%E5%BE%AA%E7%8E%AF%E4%B8%AD">疊代器在 for 循環中</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E4%B8%8E%E5%AD%97%E5%85%B8">疊代器與字典</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E4%B8%8E%E6%96%87%E4%BB%B6">疊代器與檔案</a>

<a href="#%E5%88%9B%E5%BB%BA%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%AF%B9%E8%B1%A1">建立疊代器對象</a>

<a href="#%E5%88%9B%E5%BB%BA%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%A7%94%E6%89%98%E8%BF%AD%E4%BB%A3">建立疊代對象并實作委托疊代</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%9A%84%E5%A4%9A%E6%AC%A1%E8%BF%AD%E4%BB%A3">疊代器的多次疊代</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90">清單解析</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90%E7%9A%84%E6%A0%B7%E4%BE%8B">清單解析的樣例</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90%E5%92%8C%E8%BF%AD%E4%BB%A3%E5%99%A8">清單解析和疊代器</a>

疊代器是一個含有 <code>next()</code> 方法的對象,讓我們可以疊代不是序列資料類型但表現出序列行為的對象,是以可以說疊代器為類序列對象提供了一個類序列的接口(隻要是實作了 <code>__iter__()</code> 方法的對象,就可以使用疊代器來進行通路)。疊代器從對象的第一個元素開始通路,直到所有的元素被周遊後結束。對于無法通過索引計數來随機通路元素的資料結構(EG. set)而言,疊代器是唯一的通路其自身元素的方式。

NOTE1: 但疊代器是不支援索引計數的,是以疊代器不能回退,隻能往前進行疊代。

NOTE2: 疊代器也不是線程安全的,在多線程環境中對可變對象使用疊代器是一個危險的操作。是以一般情況下應該堅持對不可變對象實作疊代器。

NOTE3: 疊代器對象不支援被多次疊代

iter(…)

iter(collection) -&gt; iterator

iter(callable, sentinel) -&gt; iterator

1. 如果傳遞了一個序列(sequence)實參,疊代器會從索引 0 一直疊代至結束。

2. 如果傳遞了兩個實參 EG. <code>iter(func, sentinel)</code>,疊代器會重複的調用 func 直到疊代器的下一個值為 sentinel 。

EXAMPLE 1:

疊代器通過其内建的 <code>iter.next()</code> 方法,或通過 Python 内建的 <code>next()</code> 來疊代下一個元素,直到最後觸發 <code>StopIteration</code> 異常後表示疊代結束。

EXAMPLE 2: 捕獲異常

EXAMPLE 3: 對 EXAMPLE 2 的改進

Python 在 for 循環的文法糖中,讓 for 循環能夠自動的調用疊代器的 <code>next()</code> 方法以及捕獲 <code>StopIteration</code> 異常。

字典是一個可疊代對象,其疊代器會變量它的 key, 是以我們可以應用這個特性将語句 <code>for eachKey in myDict.keys()</code> 改進為 <code>for eachKey in myDict</code>

EXAMPLE 4:

檔案也是一個可疊代對象,疊代器會自動的調用檔案對象的 <code>readline()</code> 方法,是以可以将語句 <code>for eachLine in myFile.readlines()</code> 修改為 <code>for eachLine in myFile</code>

EXAMPLE 5:

EXAMPLE 6: 一個斐波那契數列

Output:

将執行個體化語句 <code>fab = Fab(5)</code> 修改成 <code>fab = Fab(100)</code> 後執行,再看看 Output:

NOTE: 這一類的應用場景會對記憶體造成非常大的負擔,建議使用疊代器來減少記憶體的壓力。

EXAMPLE 6 中的 <code>__iter__()</code> 方法 return 了自己,是以疊代的對象就是自身。除此之外,我們還可以實作 委托疊代。

委托疊代:就是将疊代請求委托到疊代對象内部持有的容器對象上。它能讓自己建立的新容器能夠完成疊代操作。

EXAMPLE 7:

EXAMPLE 7 是一個樹結構,執行自身(root),傳回子節點(Node(1)、Node(2)) 。這個例子,當我們 for 循環周遊疊代器對象 root 時,實際上是疊代了 <code>self._children = [Node(1), Node(2)]</code>,這就是疊代委托。

在上文寫到,疊代器不支援被多次疊代,這樣實在不能說是靈活。為了解決這一個問題,引入了可疊代對象(iterables)和疊代器對象(iterator)兩個不同的概念。

疊代器對象:<code>__iter__()</code> 傳回的是疊代器對象自身。

可疊代對象:<code>__iter__()</code> 傳回了一個疊代器對象。

上述的 委托疊代 就是一個傳回一個疊代器對象的例子,是以 EXAMPLE 7 是一個 可疊代對象,他能夠被多次疊代。

是一個非常有用、簡單且靈活的工具,讓我們能夠動态的建立清單類型對象。

文法:

上面兩條語句的效果是一樣的,但清單解析的方法僅調用一次 <code>range(10)</code>, 而第二條則調用了 <code>map()/lambda/range(10)</code>,這說明清單解析可以替代 map() 以及 lambda ,以此來擷取更高的效率。

嵌套 for 循環實作的矩陣

統計檔案單詞數

求素數

嵌套清單降維

因為 for 循環的關系,是以從上面的例子可以看出清單解析和疊代器之間的關系非常緊密。深入的了解兩者,對提高 Python 程式的效率有非常大的幫助。疊代是 Python 一個非常重要的思想和特性。