Python 進階_迭代器 & 列表解析
目錄
迭代器
迭代器是一個含有 next()
方法的物件,讓我們可以迭代不是序列資料型別但表現出序列行為的物件,所以可以說迭代器為類序列物件提供了一個類序列的介面(只要是實現了 __iter__()
方法的物件,就可以使用迭代器來進行訪問)。迭代器從物件的第一個元素開始訪問,直到所有的元素被遍歷後結束。對於無法通過索引計數來隨機訪問元素的資料結構(EG. set)而言,迭代器是唯一的訪問其自身元素的方式。
NOTE1: 但迭代器是不支援索引計數的,所以迭代器不能回退,只能往前進行迭代。
NOTE2: 迭代器也不是執行緒安全的,在多執行緒環境中對可變物件使用迭代器是一個危險的操作。所以一般情況下應該堅持對不可變物件實現迭代器。
NOTE3: 迭代器物件不支援被多次迭代
In [19]: a = ListIter([1,2,3,4,5])
In [20]: [i for i in a]
Out[20]: [1, 2, 3, 4, 5]
In [21]: [i for i in a]
Out[21]: []
In [22]:
iter() :內建的迭代器生成函式
iter(…)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
1. 如果傳遞了一個序列(sequence)實參,迭代器會從索引 0 一直迭代至結束。
2. 如果傳遞了兩個實參 EG. iter(func, sentinel)
,迭代器會重複的呼叫 func 直到迭代器的下一個值為 sentinel 。
EXAMPLE 1:
In [44]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [45]: aIter = iter(aList)
In [46]: aIter.next()
Out[46]: 'jmilkfan'
In [47]: aIter.next()
Out[47]: 'fanguiju'
In [48]: next(aIter)
Out[48]: 'chocolate'
In [49]: aIter.next()
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-49-5ab62b0e2847> in <module>()
----> 1 aIter.next()
StopIteration:
迭代器通過其內建的 iter.next()
方法,或通過 Python 內建的 next()
來迭代下一個元素,直到最後觸發 StopIteration
異常後表示迭代結束。
EXAMPLE 2: 捕獲異常
In [56]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [57]: aIter = iter(aList)
In [58]: while True:
...: try:
...: print aIter.next()
...: except StopIteration:
...: print 'Done'
...: break
...:
jmilkfan
fanguiju
chocolate
Done
迭代器在 for 迴圈中
EXAMPLE 3: 對 EXAMPLE 2 的改進
In [59]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [60]: aIter = iter(aList)
In [61]: for x in aIter:
...: print x
...:
jmilkfan
fanguiju
chocolate
Python 在 for 迴圈的語法糖中,讓 for 迴圈能夠自動的呼叫迭代器的 next()
方法以及捕獲 StopIteration
異常。
迭代器與字典
字典是一個可迭代物件,其迭代器會變數它的 key, 所以我們可以應用這個特性將語句 for eachKey in myDict.keys()
改進為 for eachKey in myDict
EXAMPLE 4:
In [62]: aDict = {'name':'jmilkfan', 'sex':'man'}
In [69]: for x in aDict:
...: print ''.join([x,': ',aDict[x]])
...:
name: jmilkfan
sex: man
迭代器與檔案
檔案也是一個可迭代物件,迭代器會自動的呼叫檔案物件的 readline()
方法,所以可以將語句 for eachLine in myFile.readlines()
修改為 for eachLine in myFile
EXAMPLE 5:
myFile = open('FILENAME')
for eachLine in myFile:
print eachLine
myFile.close()
建立迭代器物件
EXAMPLE 6: 一個斐波那契數列
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()
if __name__ == '__main__':
fab = Fab(5)
print fab
for x in fab:
print x
Output:
In [79]: run demo_1.py
<__main__.Fab object at 0x00000000047CDE80>
1
1
2
3
5
將例項化語句 fab = Fab(5)
修改成 fab = Fab(100)
後執行,再看看 Output:
1
.
.
.
354224848179261915075
NOTE: 這一類的應用場景會對記憶體造成非常大的負擔,建議使用迭代器來減少記憶體的壓力。
EXAMPLE 6 中的 __iter__()
方法 return 了自己,所以迭代的物件就是自身。除此之外,我們還可以實現 委託迭代。
建立迭代物件並實現委託迭代
委託迭代:就是將迭代請求委託到迭代物件內部持有的容器物件上。它能讓自己建立的新容器能夠完成迭代操作。
EXAMPLE 7:
class Node:
def __init__(self, value):
self._value = value
self._children = [] # 迭代物件所持有的容器物件
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self, node):
self._children.append(node)
def __iter__(self):
return iter(self._children) # 將迭代請求轉發給迭代物件內部所持有的容器物件
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root: # 呼叫 Node:__iter__()
print(ch) # 呼叫 Node:__repr__()
Output:
Node(1)
Node(2)
EXAMPLE 7 是一個樹結構,執行自身(root),返回子節點(Node(1)、Node(2)) 。這個例子,當我們 for 迴圈遍歷迭代器物件 root 時,實際上是迭代了 self._children = [Node(1), Node(2)]
,這就是迭代委託。
迭代器的多次迭代
在上文寫到,迭代器不支援被多次迭代,這樣實在不能說是靈活。為了解決這一個問題,引入了可迭代物件(iterables)和迭代器物件(iterator)兩個不同的概念。
-
迭代器物件:
__iter__()
返回的是迭代器物件自身。 -
可迭代物件:
__iter__()
返回了一個迭代器物件。
上述的 委託迭代 就是一個返回一個迭代器物件的例子,所以 EXAMPLE 7 是一個 可迭代物件,他能夠被多次迭代。
In [1]: run demo_1.py
Node(1)
Node(2)
In [2]: run demo_1.py
Node(1)
Node(2)
列表解析
是一個非常有用、簡單且靈活的工具,讓我們能夠動態的建立列表型別物件。
語法:
[expr for iter_variable in iterable]
EXAMPLE 1:
In [18]: [x**2 for x in range(10)]
Out[18]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
In [80]: map(lambda x:x ** 2, range(10))
Out[80]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
上面兩條語句的效果是一樣的,但列表解析的方法僅呼叫一次 range(10)
, 而第二條則呼叫了 map()/lambda/range(10)
,這說明列表解析可以替代 map() 以及 lambda ,以此來獲取更高的效率。
列表解析的樣例
- 巢狀 for 迴圈實現的矩陣
In [81]: [(x+1, y+1) for x in range(3) for y in range(5)]
Out[81]:
[(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(2, 5),
(3, 1),
(3, 2),
(3, 3),
(3, 4),
(3, 5)]
- 統計檔案單詞數
f = opem('FILENAME', 'r')
len([word for line in f for word in line.split()])
- 求素數
[x for x in range(2,100) if not [y for y in range(2,int(x/2+1)) if x % y == 0]]
- 巢狀列表降維
In [143]: nestLi = [[1,2,3],[4,5,6],[7,8,9]]
In [144]: newLi = [x for para in nestLi for x in para]
In [145]: newLi
Out[145]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
列表解析和迭代器
因為 for 迴圈的關係,所以從上面的例子可以看出列表解析和迭代器之間的關係非常緊密。深入的理解兩者,對提高 Python 程式的效率有非常大的幫助。迭代是 Python 一個非常重要的思想和特性。
相關文章
- Python進階:迭代器與迭代器切片Python
- Python 函式進階-迭代器Python函式
- python手記(11)------並行迭代+列表解析Python並行
- Python——迭代器的高階用法Python
- Python3 迭代器深入解析Python
- python高階特性:切片/迭代/列表生成式/生成器Python
- Python基礎(08):迭代器和解析Python
- Python 迭代器Python
- Python迭代器Python
- Python: 列表、陣列及迭代器切片的區別及聯絡Python陣列
- Python可迭代的物件與迭代器Python物件
- python-進階教程-通過公共鍵對字典列表排序Python排序
- python中的迭代器Python
- 深度理解Python迭代器Python
- Rust 程式設計影片教程(進階)——003_1 迭代器介紹Rust程式設計
- Rust 程式設計影片教程(進階)——003_3 自定義迭代器Rust程式設計
- Python之可迭代物件、迭代器、生成器Python物件
- Python進階Python
- 結合案例深入解析迭代器模式模式
- Python 擴充之迭代器Python
- Python學習迭代器(Iterator)Python
- Python Rust 迭代器對比PythonRust
- python 生成器&迭代器Python
- python迭代器是什麼Python
- Python迭代器生成器,私有變數及列表字典集合推導式(二)Python變數
- Python3中的列表生成式、生成器與迭代器例項詳解Python
- Rust 程式設計視訊教程(進階)——003_1 迭代器介紹Rust程式設計
- Rust 程式設計視訊教程(進階)——003_3 自定義迭代器Rust程式設計
- Android ListView 進階——從列表中獲取值AndroidView
- Python進階之閉包和裝飾器Python
- Python函數語言程式設計系列012:惰性列表之生成器與迭代器Python函數程式設計
- Python迭代器與生成器Python
- python_August(迭代器、生成式)Python
- Python中迭代器的實現Python
- 迭代器模式大幅提升Python效能模式Python
- Python進階 — matplotlibPython
- Python進階之道Python
- Python進階 -- matplotlibPython
- Python迭代器&生成器&裝飾器Python