本文參考 景霄大神的《python核心技術與實戰》python
一 、python中的容器、可迭代對象、迭代器的使用
容器: python中一切皆對象, 對象的抽象就是類, 而對象的集就是容器,因此列表, 元祖,字典等都是容器,而且全部的容器都是能夠迭代的(iterable)
迭代器: 迭代器(iterator)提供了next的方法, 調用這個方法會獲得迭代器的下一個對象,直到取完拋出StopIteration錯誤類型,因此能夠經過可迭代對象調取next方法完成遍歷迭代器。
能夠經過isinstance校驗是否爲可迭代對象isinstanstance(obj, lterable)
二 、生成器
通俗的解釋是懶人的迭代器, 在使用迭代器構成中全部的元素都會直接一次保存在內存中,可是生成器全部的元素經過調取next動態生成, 直觀的感覺就是節省了不少資源
舉例:生成一億的迭代器[for i in range(10000000000)],可是在實際運用中並不會使用到每一個元素, 這個時候用生成器替代迭代器會更高效,也並不會報OOM異常, 生成器寫法 ( for i in range(100000000))
做用:迭代器和生成器二者區別還不止內存消耗,迭代器是有窮的,可是由於生成器是動態生成元素,理論上它是能夠無限生成下一個元素的,
實例1 計算 (1 + 2 + 3 + ... + n)
def generator(k):
i = 1
while True:
yield i ** k
i = i + 1
gen = gennerator(1)
def get_sum(n):
sum = 0
for i in range(n):
_next = next(gen)
print(_next)
複製代碼
就跟這個公式同樣, n能夠取無窮, 一樣理論上生成器也能夠取無窮, 上述代碼用yield暫停了函數,而且跳轉到next()函數, i ** k 即爲next返回值, yield的用法還有不少, 能夠代替線程用協程的方法完成函數塊的切換,省去了線程間切換消耗的資源,能夠用send激活, 這邊講了其中一種用法, 一樣它也就是用next激活了生成器。
實例2 在列表中查找某個數字的位置
def func1(list, k):
out_list = []
for i, num in enumerate(list):
if num == k:
print('fonud it ', i)
def func2(list, k):
for i, num in enumerate(list):
if num == k:
yield i
複製代碼
ps: func2就是生成了一個迭代器對象, 再轉list就能夠了, 可讓代碼更加有可讀性。markdown
實例3 查找列表中是否包含子列表
def is_instance(check_list, list):
list = iter(list)
return all( i in list for i in check_list) # all()函數必須全部返回均爲True纔會返回True
複製代碼
3、總結
- 容器是可迭代對象, 可迭代對象調用iter()函數能夠獲得一個迭代器, 迭代器經過next()獲得下一個元素, 從而支持遍歷, 注意點: 迭代器遍歷只可使用一次,緣由是由於迭代器會存到緩衝區內, 經過移動指針來消耗緩衝區, 隨時讀取,可是讀過一次以後指針就在緩衝區的末尾, 因此不可重複讀取。
- 生成器是一種特殊的迭代器,合理使用生成器能夠下降內存佔用,優化程序結構,提升程序運行速度。
- 生成器也是在python2中協程的一種重要的實現方式(在python中因爲GIL的存在每每使用多進程+協程的方式實現併發), 而在python3.5以上引用了async await語法糖