1. 程式人生 > >python協程函數應用 列表生成式 生成器表達式

python協程函數應用 列表生成式 生成器表達式

錯誤 擴展 存儲 ini 是否 釋放 lba func 斷點

協程函數應用 列表生成式 生成器表達式

一、知識點整理:

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 = yield
12         print("%s eat %s"%(name,food))
13 e  = eater("zhejiangF4")
14 e.send("something")   #直接傳值
技術分享

執行結果:

1 zhejiangF4 start to eat
2 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 @init
10 def search(target):
11     ‘找到文件的絕對路徑‘
12     while True:
13         dir_name=yield
14         #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 @init
22 def opener(target):
23     ‘打開文件,獲取文件句柄‘
24     while True:
25         file_path = yield
26         #print(‘車間opener開始生產產品:文件句柄‘)
27         time.sleep(1)
28         with open(file_path) as f:
29             target.send((file_path,f))
30 @init
31 def cat(target):
32     ‘讀取文件內容‘
33     while True:
34         file_path,f = yield
35         #print(‘車間cat開始生產產品:文件的一行內容‘)
36         time.sleep(1)
37         for line in f:
38             target.send((file_path,line))
39 @init
40 def grep(pattern,target):
41     ‘過濾一行內容中有無python‘
42     while True:
43         file_path,line = yield
44         #print(‘車間grep開始生產產品:包含python這一行內容的文件路徑‘)
45         time.sleep(0.2)
46         if pattern in line:
47             target.send(file_path)
48 @init
49 def printer():
50     ‘打印文件路徑‘
51     while True:
52         file_path = yield
53         #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.txt
2 G:\zhang\a1\a1.txt
3 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 10
2 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.0
3 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協程函數應用 列表生成式 生成器表達式