ql的python学习之路-day10
前言:本節主要講解迭代器和生成器
迭代器&生成器
一、生成器(generator)
循環占用大部分的容量內存,如果只需要循環前面的幾個結果那怎么樣做呢,在python中有一種一邊循環一邊計算的機制,稱為生成器:generator,就能解決這個問題。
生成器只有在調用的時候才會產生相應的數據,用__next()__方法調用(2.7版本里是next()),生成器只能記錄當前的位置,不能后退也不能記錄以后的數據。
實例:斐波那契數列中的生成器
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:qinjiaxi 4 def fib(max): 5 n, a, b = 0, 0, 1#初始化 6 while n < max:#循環 7 yield b 8 #print(b)#打印b 9 a, b = b, a + b 10 n += 1 11 return "done"#異常的時候打印的消息 12 13 #抓異常 14 g = fib(6) 15 while True: 16 try: 17 x = next(g) 18 print("g:", x) 19 except StopIteration as e: 20 print("Generator return value:", e.value) 21 break 22 #調用生成器 23 f = fib(10) 24 print(f)#打印生成器對象的內存地址 25 print(next(f))#取第一個值 26 print(f.__next__())#取第二個值 27 print(next(f))#取第三個值 28 print("---start loop---") 29 for i in f:#循環取剩下的數據 30 print(i) 31 #注:當用next()方法調用次數超過設定值時,會產生異常 32 33 #理解其中的a, b = b, a + b 34 t = (b, a + b)#實際有個臨時變量t,t是一個元組 35 a = t[0] 36 b = t[1] 37 #t不會顯式的出現在代碼中生成器實際工作中的應用:協程(單線程并行處理),異步io處理
yeild作用是保存當前狀態并返回,無返回值(返回值是None)
next方法調用yield,send方法調用yield并給yield傳值,yield后面加上一個變量,可以返回變量
協程1源碼:
1 #!/user/bin/env python 2 #-*-coding:utf-8 -*- 3 #Author: qinjiaxi 4 import time 5 def consumer(name): 6 print("%s準備吃包子了" % name) 7 while True: 8 baozi = yield 9 print("包子[%s]被%s吃了" % (baozi, name)) 10 11 c = consumer('ql') 12 #next(c)#停在yield位置(中斷,返回迭代值) 13 #c.__next__()#從yield下一句開始執行,用于默認沒有給yield傳遞參數所以返回的是None,執行完后又回到yield這一行 14 #c.__next__() 15 #c.send("韭菜餡的")#send方法可以調用yield并且給yield傳送參數 16 17 def producer(name): 18 c = consumer('A') 19 c1 = consumer('B') 20 c.__next__()#A準備吃包子了 21 c1.__next__()#B準備吃包子了 22 print("%s開始做包子了" % name) 23 for i in range(10): 24 time.sleep(1) 25 print("做了一個包子分兩半") 26 c.send(i)#傳遞i到A的yield,給A的yield賦值 27 c1.send(i)#傳遞i到B的yield,給B的yield賦值 28 producer('qinlang')協程2源碼:
1 #!/user/bin/env python 2 #-*-coding:utf-8 -*- 3 #Author: qinjiaxi 4 import time 5 def consumer(): 6 r = ''#初始化r 7 while True: 8 n = yield r#將值傳給n,然后執行下一句,碰到r變量再返還r給producer函數 9 print("[consumer] is consuming %s " % n) 10 r = '200 is ok' 11 12 def producer(c): 13 c.send(None) 14 n = 0 15 while n < 5: 16 n = n + 1 17 time.sleep(1) 18 print("[producer] is producting %s" % n) 19 r = c.send(n) 20 print("[producer] cousumer return %s" % r) 21 # for i in range(6): 22 # time.sleep(1) 23 # print('[producer] is producing %s ' % i) 24 # r = c.send(i)#傳n值給生成器yield 25 # print('[producer] consumer return %s' % r) 26 c.close()#關閉生成器 27 c = consumer() 28 producer(c)?
結論:
一個帶有yield的函數就是一個generator,它和普通函數不一樣,生成器generator看起來像函數,其實不會執行任何函數代碼,直到對其調用next()方法(在for循環中會自動調用next()方法)才會執行。雖然執行仍然像函數一樣執行,其實當執行到yield時候就會中斷并返回一個迭代值,當再次調用next()方法時從yield下一句開始執行。看起來就好像一個函數在正常執行的時候被yield中斷了數次,每次中斷都會通過yield返回迭代值。
二、迭代器(Iterator)
我們知道能直接作用于for循環的數據類型有以下幾種:
一類是集合數據類型,如list、tuple、str、set、dict
一類是generator,包括生成器和帶yield的generator function
*這些可以直接作用于for循環的對象統稱為可迭代對象:Iterable
可以使用isinstance()來判斷一個對象是否是iterable對象:
1 >>> from collections import Iterable 2 >>> isinstance([], Iterable) 3 True 4 >>> isinstance('abc', Iterable) 5 True 6 >>> isinstance({}, Iterable) 7 True 8 >>> isinstance((i for i in range(10)), Iterable) 9 True 10 >>> isinstance(100, Iterable) 11 False生成器不但可以作用于for循環,還可以被next()函數不斷的調用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續返回下一個值。
*可以被next()函數調用并且不斷返回下一個值的對象稱為迭代器:Iterator
可以使用isinstance()來判斷一個對象是否是interator對象:
1 >>> from collections import Iterator 2 >>> isinstance([], Iterator) 3 False 4 >>> isinstance({}, Iterator) 5 False 6 >>> isinstance((i for i in range(10)), Iterator) 7 True由上可知生成器都是Iterator對象,但list、dict、str雖然是Iterable但不是Iterator。
把list、dict、str等Iterable變成Iterator可以使用iter()函數:
1 >>> isinstance(iter([]), Iterator) 2 True 3 >>> isinstance(iter('abc'), Iterator) 4 True 5 >>> isinstance(iter({}), Iterator) 6 True?為什么list、dict、str等數據不是Iterator?
因為python的Iterator對象表示的是一個數據流,Iterator對象可以被next()函數調用并不斷的返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可以把數據流看做是一個有序序列,但是我們提前并不知道序列的長度,只有通過next()函數按需繼續下一個數據,所以Iterator的計算是惰性的,只有在需要返回下一個數據的時候才計算。
Iterator甚至可以表示一個無限大的數據流,例如全體自然數。但是list是永遠不可能村粗全體自然數的。
小結:
凡是可作用于for循環的對象都是Iterable類型(可迭代類型);
凡是可以作用于next()函數的對象都是Iterator類型(迭代器類型),它們表示一個惰性的計算序列;
集合數據類型例如list、dict、str等都是Iterable(可迭代對象)但不是Iterator(迭代器),可以通過iter()函數獲得一個迭代對象。
Python的for循環的本質就是不斷的通過調用next()函數實現的。
python3.0中range(10)其實是一個迭代器
python2.x中xrange(10)是迭代器
?
轉載于:https://www.cnblogs.com/qinlangsky/p/9551666.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的ql的python学习之路-day10的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: qt 提高图片加载速度
- 下一篇: Perl的输出:print、say和pr