python學習筆記——生成器和迭代器
阿新 • • 發佈:2018-11-15
一、生成器
- 計算機的儲存資源一向是很寶貴的,在對大量的資料進行計算時,如果是把資料統一讀到記憶體中來在進行計算就會造成大量的資源浪費。用生成器來進行算計時採用是一邊迴圈一邊計算的方式,不用一下將資料讀入記憶體,節約大量記憶體空間。
- 舉個簡單的列子說明:
- 生成一個列表,並輸出列表各項乘以2的值,可用 [i*2 for i in range(10)] 來實現.
- 當上個語句改為 (i*2 for i in range(100)) 時就成為了一個生成器,只有當迴圈到第i個值的時候i的資料才生成並被計算,且生成器只記住當前位置無法查詢前一個數值。
- 生成一個列表,並輸出列表各項乘以2的值,可用 [i*2 for i in range(10)] 來實現.
- 生成器只有兩種呼叫方式
c = (i*2 for i in range(100)) # 計算100個隨機數乘以2的值 for i in c: # 利用迴圈呼叫生成器 print(i) print('------other method-------') for i in range(100): n = c.__next__() # 使用c.__next__()語句呼叫生成器,當生成器本身有輸出時常用此種呼叫方式 print(n)
- 當資料複雜時可利用函式構成生成器,需要使用yield作為函式的輸出或者返回值,一個小例子,斐波那契數列,從第三個數開始後一個數等於前兩數之和
#
- 上述生成器可加入return語句作為抓取異常的返回資訊,以上數程式舉例,當使用print(c.__next__())呼叫生成器時超過了生成器的迴圈值會報StopIteration(異常停止)的錯,可使用下列程式抓取錯誤並處理
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b # 返回當前值並暫停運算 a, b = b, a+b # a=b,b=a+b相當於t=(b,a+b),t(0)=a,t(1)=a+b,用於累加 n = n+1 return '-----done' # 出現異常時列印訊息 c = fib(10) # 將函式賦成的生成器賦值於變數 print(c.__next__()) # 呼叫超過10次的錯誤操作 print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) print(c.__next__()) g= fib(6) # 呼叫函式並傳遞引數 while True: # 建立死迴圈不斷抓取 try: x = next(g) print('g:', x) except StopIteration as e: # 遇到StopIteration錯誤將它命名為e print('StopIteration return value', e.value) # 列印錯誤資訊,及return的值 break
- 單執行緒的生成器並行,程式碼說明
# ########單執行緒生成器並行######## import time def consumer(name): print("%s要吃麵" % name) while True: mian = yield # 程式執行暫停,等待再次被喚醒執行下面的程式碼 print('%s面來了,被%s吃光了' % (mian, name)) c = consumer('mina') c.__next__() # 喚醒生成器 # ######c.send(引數)可在喚醒生成器的時候將引數傳遞給yield########### def producer(name): c1 = consumer('A') c2 = consumer('B') c1.__next__() c2.__next__() print('%s開始下面' % name) for i in range(10): time.sleep(1) print('下了1碗麵') c1.send(i) # 喚醒生成器並將i的值傳遞給yield c2.send(i) producer('minax')
此時應注意c.send()只適合於並行時使用
二、迭代器(Iterator)
- 可迭代物件:可直接作用於for迴圈的物件統稱為可迭代物件,並且可使用isinstance(self,TIterable)判斷物件是否可迭代。
from collections.abc import Iterable # 將Iterable模組匯入,3.8版本使用,之前的版本為from collections import Iterable print(isinstance((x for x in range(10)), Iterable)) # 結果為True
- 迭代器:可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器
d = (x for x in range(10)) # 一個迭代器 print(next(d)) # 輸出0 print(next(d)) # 輸出1
- 字典、列表、字串、元組等可用iter()變為迭代器
from collections.abc import Iterable # 將Iterable模組匯入,3.8版本使用,之前的版本為from collections import Iterable c = [1, 2, 3, 4] iter(c) print(isinstance(c, Iterable))
三、內建引數/方法
- 匿名函式,即可不用命名函式
call = lambda n: print(n) # 相當於{def s(n): print(n)}s(5) call(5) (lambda n:print(n))(5) # 另一種設定方式
- 過濾,例如過濾出大於5的列表,可利用匿名函式
a = filter(lambda n: n > 5, range(1, 10)) # n從1到10依次取大於5的值 c = list(a) # 可用list得到filter過濾器返回的一個可迭代物件 print(c) # 結果為[6, 7, 8, 9]
- 按指定方式處理值,即map的使用,與過濾相似
c = map(lambda n: n*n, range(10)) # 使用map按指定方式處理n值 print(list(c)) # 輸出[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
另一種,使用function標準庫,如計算階乘,需使用兩個變數
import functools # python3.8裡用的functools,以前版本好像是用的function來著 reg = functools.reduce(lambda x, y: x*y, range(1, 10)) # 實現階乘 print(reg) # 輸出為362880
四、json序列化模組,將字典、列表等轉為字串存入檔案,也可以反向執行
- 程式碼說明
# ##########json########## import json info = { 'name': 'mina', 'age': 18 } # 定義一個字典 with open('test.text', 'w') as f: # 以寫模式建立一個檔案 f.write(json.dumps(info)) # 將字典利用json模組寫入檔案中,結果為{"name": "mina", "age": 18}
將檔案中的字串轉為對應字典或陣列
with open('test.text', 'r') as c: # 以讀模式開啟檔案 data = json.loads(c.read()) # 將檔案中的字串下載並轉為字典 print(data['name']) # 利用字典的查詢方式輸出‘mina’