標籤:基礎 文法 區別 優點 迴圈 ken 應用 toolbar rip
一、知識點整理:
1、可迭代的:對象下有_iter_方法的都是可迭代的對象
迭代器:對象._iter_()得到的結果就是迭代器
迭代器的特性:
迭代器._next_() 取下一個值
優點:
1.提供了一種統一的迭代對象的方式,不依賴於索引
2.惰性計算
缺點:
1.無法擷取迭代器的長度
2.一次性的,只能往後取值,不能往前退,不能像索引那樣去取得某個位置的值
2、產生器:函數內帶有yield關鍵字,那麼這個函數執行的結果就是產生器
產生器的本質就是迭代器
def func():
n=0
while True:
yield n
n+=1
g = func()
next(g)
3、總結yield的功能:
1、相當於把_iter_和_next_方法封裝到函數內部
2、與return比,return只能返回一次,而yield能返回多次
3、函數暫停以及繼續啟動並執行狀態是通過yield儲存的
4、yield的運算式形式: 如:food = yield
def eater(name):
print("%s start to eat"%name)
while True:
food = yield
print("%s eat %s"%(name,food))
e = eater("zhejiangF4")
next(e)
e.send("aaa")
5、e.send 與 next(e)的區別
#1.如果函數內yield是運算式形式,那麼必須先next(e)
#2.二者的共同之處是都可以讓函數在上一次暫停位置繼續運行,不一樣的地方在於send在觸發下一次代碼的執行時,會順便給yield傳一個值
二、產生器 協程函數的應用
1、編寫一個裝飾器,在不變更原代碼 協程函數 的基礎上,直接就能給主函數傳值!(協程函數第一步需要next()觸發,既將觸發寫入裝飾器中!)
1 def f(func): #定義裝飾器 2 def f1(*args,**kwargs): 3 res = func(*args,**kwargs) 4 next(res) #觸發主函數 5 return res 6 return f1 7 @f 8 def eater(name): #主函數 9 print("%s start to eat"%name)10 while True:11 food = yield12 print("%s eat %s"%(name,food))13 e = eater("zhejiangF4")14 e.send("something") #直接傳值
執行結果:
1 zhejiangF4 start to eat2 zhejiangF4 eat something
##在IDE上加上斷點,debug運行查看##
2、遞迴目錄,過濾檔案中帶有“python”內容的檔案,然後將這些檔案列印。此段代碼實現功能,牽扯到面向過程編程的思想!定義的每一個函數都是環環相扣,猶如一個完整的生產線一樣!
面向過程的編程思想:流水線式的編程思想,在設計程式時,需要把整個流程設計出來
#優點:
1、體繫結構更加清晰
2、簡化程式的複雜度
#缺點:
1、可擴充性極其的差,所以說面向過程的應用情境是:不需要經常變化的軟體。
1 import os,time 2 def init(func): 3 def wrapper(*args,**kwargs): 4 res = func(*args,**kwargs) 5 next(res) 6 return res 7 return wrapper 8 9 @init10 def search(target):11 ‘找到檔案的絕對路徑‘12 while True:13 dir_name=yield14 #print(‘車間search開始生產產品:檔案的絕對路徑‘)15 time.sleep(1)16 g = os.walk(dir_name)17 for i in g:18 for j in i[-1]:19 file_path = "%s\\%s"%(i[0],j)20 target.send(file_path)21 @init22 def opener(target):23 ‘開啟檔案,擷取檔案控制代碼‘24 while True:25 file_path = yield26 #print(‘車間opener開始生產產品:檔案控制代碼‘)27 time.sleep(1)28 with open(file_path) as f:29 target.send((file_path,f))30 @init31 def cat(target):32 ‘讀取檔案內容‘33 while True:34 file_path,f = yield35 #print(‘車間cat開始生產產品:檔案的一行內容‘)36 time.sleep(1)37 for line in f:38 target.send((file_path,line))39 @init40 def grep(pattern,target):41 ‘過濾一行內容中有無python‘42 while True:43 file_path,line = yield44 #print(‘車間grep開始生產產品:包含python這一行內容的檔案路徑‘)45 time.sleep(0.2)46 if pattern in line:47 target.send(file_path)48 @init49 def printer():50 ‘列印檔案路徑‘51 while True:52 file_path = yield53 #print(‘車間printer開始生產產品:得到最終的產品‘)54 time.sleep(1)55 print(file_path)56 g = search(opener(cat(grep(‘python‘,printer()))))57 g.send(‘G:\\zhang‘)
執行結果:
1 G:\zhang\a3.txt2 G:\zhang\a1\a1.txt3 G:\zhang\a2\a2.txt
三、列表產生式
1、由來
在實際編程的情況中,我們常常需要產生一些列表。除了比較低效的用for迴圈來一個一個往列表中append外,另一個比較好的方法就是:
python給我們提供了非常強大的建立列表的方式。
2、文法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
for item3 in iterable3 if condition3
for itemN in iterableN if conditionN]
通俗的來講,列表產生式由三部分拼接組成:當然每次寫之前都應該先給出[],然後在裡邊添加。
1.expression 指要產生的元素(參數,變數),放在最前面
2.後面跟上for迴圈
3.for迴圈之後還可以加上if條件判斷,以便進行篩選。
實際使用的過程中,若一個for迴圈不能完成問題,還可以往下嵌套。
1)簡單代碼舉例:
1 egg_list=[]2 for i in range(10):3 egg_list.append("egg%s"%i)4 print(egg_list)5 6 l=["egg%s"%i for i in range(10)]7 print(l)
執行結果:
1 [‘egg0‘, ‘egg1‘, ‘egg2‘, ‘egg3‘, ‘egg4‘, ‘egg5‘, ‘egg6‘, ‘egg7‘, ‘egg8‘, ‘egg9‘]2 [‘egg0‘, ‘egg1‘, ‘egg2‘, ‘egg3‘, ‘egg4‘, ‘egg5‘, ‘egg6‘, ‘egg7‘, ‘egg8‘, ‘egg9‘]
2)稍微有點複雜的,不過也好理解。
1 #將l 和 s 中每一個元素取出,組成一個新的元組,將所有的結果儲存在列表中 2 l = [1,2,3,4] 3 s = "hello" 4 l1 = [(num,s1) for num in l if num >3 for s1 in s] 5 print(l1) 6 7 l2 = [] 8 for num1 in l : 9 if num1 >3:10 for s2 in s :11 t = (num1 ,s2)12 l2.append(t)13 print(l2)
執行結果:
1 [(4, ‘h‘), (4, ‘e‘), (4, ‘l‘), (4, ‘l‘), (4, ‘o‘)]2 [(4, ‘h‘), (4, ‘e‘), (4, ‘l‘), (4, ‘l‘), (4, ‘o‘)]
通過比較,雖然上邊兩種方式都可以實現功能,但是可以非常明顯的看出:運用傳統意義上的迴圈,去編寫代碼是非常繁瑣複雜的。
而運用 列表產生式,同樣的內容,可以通過一個list快速產生實現功能的代碼,同時寫出的代碼非常簡潔。
3)再舉個例子:讀取檔案的絕對路徑
①代碼:
1 import os 2 g = os.walk("G:\\zhang") #拿取檔案路徑下所有的檔案 3 #print(g) #g是一個產生器 4 l = [] 5 for i in g: #擷取所有檔案的絕對路徑 6 #print(i) #路徑整體以元組的形式列印出來,元組內部是列表(檔案路徑,檔案名稱,檔案) 7 for j in i[-1]: #拿取有檔案的路徑 8 file_path = "%s\\%s" % (i[0], j) 9 l.append(file_path)10 print(l)11 12 g = os.walk("G:\\zhang")13 l1 = ["%s\\%s" %(i[0], j) for i in g for j in i[-1]]14 print(l1)
##如果不明白怎麼來的,可以將代碼拷出去,將print釋放,列印的結果即可!檔案路徑可以隨意更改!##
②執行結果:
1 [‘G:\\zhang\\a3.txt‘, ‘G:\\zhang\\a1\\a1.txt‘, ‘G:\\zhang\\a2\\a2.txt‘]
四、產生器運算式
1、定義:
產生器運算式,我個人認為還不如叫清單產生器,就是把列表運算式改變了一下,變成了一個產生器。
而且這種改變非常簡單,就是把外[]換成了()就建立了一個generator。
通過列表產生式,我們可以直接建立一個列表。但受到記憶體的限制,列表容量肯定是有限的,同時那麼龐大的資料流,一下子拿出來什麼機器得卡的受不了。
而且,建立一個包含100萬個元素的列表,不僅佔用很大的儲存空間,如果我們僅僅需要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。
所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。
在Python中,這種一邊迴圈一邊計算的機制,稱為產生器:generator。
就昨天所學的產生器的理解來判斷:generator產生器儲存的是演算法,每次通過next()觸發取值,並且每次只取一個元素的值,直到計算到最後一個元素。
沒有更多的元素時,就會拋出StopIteration的錯誤。我們可以通過for迴圈來迭代它,並且不需要關心StopIteration的錯誤。
這種產生器經常運用於:處理檔案,讀取資料庫中大量的資料 的情況之中。
1、簡單代碼舉例:
1 #還是下蛋的例子(……跟雞過不去了……) 2 l=[‘egg%s‘ %i for i in range(100)] 3 print(l) 4 5 g=l=(‘egg%s‘ %i for i in range(1000000000000000000000000000000000000)) 6 print(g) 7 print(next(g)) 8 print(next(g)) 9 for i in g:10 print(i)
執行結果:
2、處理檔案的代碼舉例:
1 #處理檔案,去除檔案中每行的空格 2 #傳統處理方式,如果資料很大的話,瞬間將記憶體擠爆…… 3 f=open(‘a.txt‘) 4 l=[] 5 6 for line in f: 7 line=line.strip() 8 l.append(line) 9 print(l)10 11 f=open(‘a.txt‘)12 f.seek(0)13 l1=[line.strip() for line in f]14 print(l1)15 16 f=open(‘a.txt‘)17 f.seek(0)18 g=(line.strip() for line in f)19 print(g)20 print(next(g))21 22 23 #list(可迭代對象) 可以將迭代器轉換成列表24 f=open(‘a.txt‘)25 g=(line.strip() for line in f)26 27 l=list(g)28 print(l)
執行結果:
View Code
3、應用:聲明式編程
1)求和函數 sum() 可以計算 可迭代的資料的值
1 #1、求和函數 sum() 可以計算 可迭代的資料的值2 print(sum([1,2,3,4])) #直接對列表求和3 nums_g=(i for i in range(3)) #產生器4 print(sum(nums_g))#求和
執行結果:
1 102 3
2)計算購物清單總價
1 # 計算購物清單總價 2 # 1、傳統方式 3 money_l=[] 4 with open(‘b.txt‘) as f: 5 for line in f: 6 goods=line.split() #將檔案中的每行以空格分割,然後以列表的形式儲存 7 res=float(goods[-1])*float(goods[-2]) #求和 個數*單價 此處注意資料類型的轉換 str -> float 8 money_l.append(res) #產生一個總價的列表 9 print(money_l) #列印列表10 print(sum(money_l))#求總價11 #12 # 2、清單產生器 方法 將上邊的代碼用聲明式編程代替13 f=open(‘b.txt‘)14 g=(float(line.split()[-1])*float(line.split()[-2]) for line in f)15 print(sum(g))16 #
執行結果:
1 [30.0, 1000000.0, 6000.0, 90000.0, 30.0]2 1096060.03 1096060.0
3)資料庫查詢的功能(檔案資料,string)得到的內容是[{},{}]形式,列表套字典的形式。
1 res=[] 2 with open(‘b.txt‘) as f: 3 for line in f: 4 # print(line) 5 l=line.split() #把每行處理成列表 6 # print(l) 7 d={} #先定義一個空字典 8 d[‘name‘]=l[0] #往字典內賦值 9 d[‘price‘]=l[1] #往字典內賦值10 d[‘count‘]=l[2] #往字典內賦值11 res.append(d) #將新建立的字典寫到列表中12 print(res) #列印結果13 #14 # 產生器運算式 方式 處理15 with open(‘b.txt‘) as f:16 res=(line.split() for line in f) #得到一個清單產生器 大列表,檔案內所有內容都在17 #print(res) #查看類型 產生器18 dic_g=({‘name‘:i[0],‘price‘:i[1],‘count‘:i[2]} for i in res) #對迭代器進行取值,拿到每個小列表,組成一個新的字典,存放在新的列表中19 print(dic_g)#查看類型 產生器20 apple_dic=next(dic_g) #取第一值 前提是知道第一個是什麼21 print(apple_dic[‘count‘])
執行結果:
1 [{‘name‘: ‘apple‘, ‘price‘: ‘10‘, ‘count‘: ‘3‘}, {‘name‘: ‘tesla‘, ‘price‘: ‘1000000‘, ‘count‘: ‘1‘}, {‘name‘: ‘mac‘, ‘price‘: ‘3000‘, ‘count‘: ‘2‘}, {‘name‘: ‘lenovo‘, ‘price‘: ‘30000‘, ‘count‘: ‘3‘}, {‘name‘: ‘chicken‘, ‘price‘: ‘10‘, ‘count‘: ‘3‘}]2 <generator object <genexpr> at 0x00000000028EB360>3 3
此處有一個非常有趣的問題,昨天所學,我們知道檔案本身就是一個迭代器。
next()取值之後,會將檔案關閉。往後就無法再取值,所以會有I/O錯誤 沒法讀取 檔案關閉的報錯。
所以調用檔案的話,建議用 f = open("b.txt") 或是next()觸發取值的話,縮近放在裡邊。
4)取出單價>10000 大體不變,只是將每行組成的列表,格式化 轉換成字典的時候進行過濾,取出滿足條件的內容
1 # 取出單價>10000 大體不變,只是將每行組成的列表,格式化 轉換成字典的時候進行過濾,取出滿足條件的內容2 with open(‘b.txt‘) as f:3 res=(line.split() for line in f)4 # print(res)5 dic_g=({‘name‘:i[0],‘price‘:i[1],‘count‘:i[2]} for i in res if float(i[1]) > 10000)6 print(dic_g)7 #print(list(dic_g)) #直接取值8 for i in dic_g: #for迴圈取值9 print(i)
執行結果:
1 <generator object <genexpr> at 0x00000000026BB3B8>2 {‘name‘: ‘tesla‘, ‘price‘: ‘1000000‘, ‘count‘: ‘1‘}3 {‘name‘: ‘lenovo‘, ‘price‘: ‘30000‘, ‘count‘: ‘3‘}
python協程函數應用 列表產生式 產生器運算式