標籤:pytho 方式 資料 sum hid 注意事項 UNC 衣服 基本
回顧python中的for迴圈
如果用索引取值,你可以取到任意位置的值,前提是你要知道這個值在什麼位置。
如果用for迴圈來取值,我們把每一個值都取到,不需要關心每一個值的位置,因為只能順序的取值,並不能跳過任何一個直接去取其他位置的值。
什麼叫迭代
“可迭代”,就應該可以被for迴圈
字串、列表、元組、字典、集合都可以被for迴圈,說明他們都是可迭代的
可以將某個資料集內的資料“一個挨著一個的取出來”,就叫做迭代。
可迭代協議
假如我們自己寫了一個資料類型,希望這個資料類型裡的東西也可以使用for被一個一個的取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。
可以被迭代要滿足的要求就叫做可迭代協議。可迭代協議的定義非常簡單,就是內部實現了__iter__方法。
迭代器iterator
迭代器遵循迭代器協議:必須擁有__iter__方法和__next__方法。
for迴圈就是基於迭代器協議提供了一個統一的可以遍曆所有對象的方法,
即在遍曆之前,先調用對象的__iter__方法將其轉換成一個迭代器,
然後使用迭代器協議去實現逐一查看,這樣所有的對象就都可以通過for迴圈來遍曆了
產生器
迭代器有兩種:一種是調用方法直接返回的,一種是可迭代對象通過執行iter方法得到的,迭代器有的好處是可以節省記憶體。
如果在某些情況下,我們也需要節省記憶體,就只能自己寫。我們自己寫的這個能實現迭代器功能的東西就叫產生器。
Python中提供的產生器:
1.產生器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行
2.產生器運算式:類似於列表推導,但是,產生器返回按需產生結果的一個對象,而不是一次構建一個結果清單
產生器Generator:
本質:迭代器(所以內建了__iter__方法和__next__方法,不需要我們去實現)
特點:惰性運算,開發人員自訂
產生器函數
一個包含yield關鍵字的函數就是一個產生器函數。yield可以為我們從函數中傳回值,但是yield又不同於return,
return的執行意味著程式的結束,調用產生器函數不會得到返回的具體的值,而是得到一個可迭代的對象。
每一次擷取這個可迭代對象的值,就能推動函數的執行,擷取新的傳回值。直到函數執行結束。
import timedef genrator_fun1(): a = 1 print(‘現在定義了a變數‘) yield a b = 2 print(‘現在又定義了b變數‘) yield bg1 = genrator_fun1()print(‘g1 : ‘,g1) #列印g1可以發現g1就是一個產生器print(‘-‘*20) print(next(g1))time.sleep(1) #sleep一秒看清執行過程print(next(g1))初識產生器函數
產生器的好處就是不會一下子在記憶體中產生太多資料
#初識產生器二def produce(): """生產衣服""" for i in range(2000000): yield "生產了第%s件衣服"%iproduct_g = produce()print(product_g.__next__()) #要一件衣服print(product_g.__next__()) #再要一件衣服print(product_g.__next__()) #再要一件衣服num = 0for i in product_g: #要一批衣服,比如5件 print(i) num +=1 if num == 5: break#到這裡我們找工廠拿了8件衣服,我一共讓我的生產函數(也就是produce產生器函數)生產2000000件衣服。#剩下的還有很多衣服,我們可以一直拿,也可以放著等想拿的時候再拿初識產生器二
import timedef tail(filename): f = open(filename) f.seek(0, 2) #從檔案末尾算起 while True: line = f.readline() # 讀取檔案中新的文本行 if not line: time.sleep(0.1) continue yield linetail_g = tail(‘tmp‘)for line in tail_g: print(line)產生器監聽檔案輸入的例子
def generator(): print(123) content = yield 1 print(‘=======‘,content) print(456) yield2g = generator()ret = g.__next__()print(‘***‘,ret)ret = g.send(‘hello‘) #send的效果和next一樣print(‘***‘,ret)#send 擷取下一個值的效果和next基本一致#只是在擷取下一個值的時候,給上一yield的位置傳遞一個資料#使用send的注意事項 # 第一次使用產生器的時候 是用next擷取下一個值 # 最後一個yield不能接受外部的值
def gen1(): for c in ‘AB‘: yield c for i in range(3): yield iprint(list(gen1()))def gen2(): yield from ‘AB‘ yield from range(3)print(list(gen2()))yield from
View Code
def averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/countg_avg = averager()next(g_avg)print(g_avg.send(10))print(g_avg.send(30))print(g_avg.send(5))計算移動平均值(1)
View Code
def init(func): #在調用被裝飾產生器函數的時候首先用next啟用產生器 def inner(*args,**kwargs): g = func(*args,**kwargs) next(g) return g return inner@initdef averager(): total = 0.0 count = 0 average = None while True: term = yield average total += term count += 1 average = total/countg_avg = averager()# next(g_avg) 在裝飾器中執行了next方法print(g_avg.send(10))print(g_avg.send(30))print(g_avg.send(5))計算移動平均值(2)_預激協程的裝飾器
View Code
列表推導式和產生器運算式
1.把列表解析的[]換成()得到的就是產生器運算式
2.列表解析與產生器運算式都是一種便利的編程方式,只不過產生器運算式更節省記憶體
3.Python不但使用迭代器協議,讓for迴圈變得更加通用。大部分內建函數,也是使用迭代器協議訪問對象的。例如, sum函數是Python的內建函數,該函數使用迭代器協議訪問對象,而產生器實現了迭代器協議,所以,我們可以直接這樣計算一系列值的和:
sum(x ** 2 for x in range(4))
而不用多此一舉的先構造一個列表:
sum([x ** 2 for x in range(4)])
其他推導式 http://www.cnblogs.com/Eva-J/articles/7276796.html
python 迭代器與產生器