目錄:python
2、函數的裝飾器app
3、迭代器函數
4、生成器spa
程序出問題的時候能夠用debug來看一下代碼運行軌跡,而後找找問題在哪裏code
1.先給即將debug的代碼打上斷點:對象
2.打完斷點以後右鍵點擊debug:blog
3.而後依次點擊開始按鈕讓程序開始一步步運行:內存
定義:裝飾器爲其餘函數添加附加功能,本質上仍是一個函數
原則:①不修改被修飾函數的源代碼
②不修改被修飾函數的調用方式
有這樣一個函數:demo()
先導入時間模塊,而後函數執行時先睡兩秒,在執行打印
1 import time 2 def demo(): 3 time.sleep(2) 4 print("welcome sir") 5 demo()
如今想爲demo()函數添加一個統計函數運行時間的功能,可是要遵循開放封閉原則
初步思想:
1 import time 2 def demo(): 3 start_time = time.time() 4 time.sleep(2) 5 print("welcome sir") 6 end_time = time.time() 7 print("運行時間%s" %(end_time-start_time)) 8 demo()
這樣就完美解決了,可是,咱們要用可持續發展的眼光來看,假若有十萬個代碼,咱們這樣一個一個添加,你不加班誰加班?
這個時候咱們能夠用函數的思惟來解決
進步思想:
1 import time 2 def demo(): 3 time.sleep(2) 4 print("welcome sir") 5 def timmer(func_name): 6 def inner(): 7 start_time = time.time() 8 func_name() 9 end_time = time.time() 10 print("運行時間%s" %(end_time-start_time)) 11 return inner 12 res = timmer(demo) 13 res()
這樣看起來很是Nice,用到了高階函數,嵌套函數,函數閉包,可是咱們違反了開放封閉原則,這個時候把res 改爲 demo 就能夠了
在這裏有一個命令,能夠直接略過這個賦值,讓代碼看起來更美觀,執行效率更高
1 import time 2 def timmer(func_name): 3 def inner(): 4 start_time = time.time() 5 func_name() 6 end_time = time.time() 7 print("運行時間%s" %(end_time-start_time)) 8 return inner 9 @timmer 10 def demo(): 11 time.sleep(2) 12 print("welcome sir") 13 demo()
ok,代碼完成,這其實就是一個函數裝飾器,咱們來解釋一下代碼運行順序
爲裝飾器加上返回值:
1 import time 2 def timmer(func_name): 3 def inner(): 4 start_time = time.time() 5 res = func_name() 6 end_time = time.time() 7 print("運行時間%s" %(end_time-start_time)) 8 return res 9 return inner 10 @timmer 11 def demo(): 12 time.sleep(2) 13 return '函數demo的返回值'
14 val = demo() 15 print(val)
有參數的裝飾器:
1 import time 2 def timmer(func_name): 3 def inner(*args,**kwargs): 4 start_time = time.time() 5 res = func_name(*args,**kwargs) 6 end_time = time.time() 7 print("運行時間%s" %(end_time-start_time)) 8 return res 9 return inner 10 @timmer 11 def demo(name,age): 12 time.sleep(2) 13 return '函數demo的返回值,姓名:%s,年齡:%s' %(name,age) 14 val = demo('zrh',20) 15 print(val)
圖示流程:
可迭代協議:只要包括了"_iter_"方法的數據類型就是可迭代的
1 print([1,2,3].__iter__()) #打印結果:<list_iterator object at 0x000002E7F803DE88>
iterable 形容詞 可迭代的
1 from collections import Iterable #檢測一個對象是否可迭代
2 print(isinstance('aaa',Iterable)) 3 print(isinstance(123,Iterable)) 4 print(isinstance([1,2,3],Iterable))
迭代器協議:迭代器中有 __next__ 和 __iter__方法
iterator 名詞 迭代器,迭代器 就是實現了能從其中一個一個的取出值來
檢測參數是否是個迭代器:
1 from collections import Iterator 2 print(isinstance(lst_iterator,Iterator)) 3 print(isinstance([1,2,3],Iterator))
在python裏,目前學過的全部的能夠被for循環的基本數據類型都是可迭代的,而不是迭代器。
迭代器包含可迭代對象
可迭代對象轉換爲迭代器:
可迭代對象._iter_() 這樣就變成可一個迭代器
lise_case = [1,2,3].__iter__()
迭代器存在的意義:
1.可以對python中的基本數據類型進行統一的遍歷,不須要關心每個值分別是什麼
2.它能夠節省內存 —— 惰性運算
for循環的本質:
1 lst_iterator = [1,2,3].__iter__() 2 while True: 3 try: 4 print(lst_iterator.__next__()) 5 except StopIteration: 6 break
只不過for循環以後若是參數是一個可迭代對象,python內部會將可迭代對象轉換成迭代器而已。
Iterator 迭代器
Gerator 生成器
生成器其實就是迭代器,生成器是用戶寫出來的
1 def generator_func(): #生成器函數
2 print(123) 3 yield 'aaa'
4 generate = generator_func() 5 print(generate) 6 print(generate.__next__()) 7 # 打印結果:
8 # <generator object generator_func at 0x0000018F3942E8C8>
9 # 123
10 # aaa
帶yield關鍵字的函數就是生成器函數,包含yield語句的函數能夠用來建立生成器對象,這樣的函數也稱爲生成器函數。
yield語句與return語句的做用類似,都是用來從函數中返回值,return語句一旦執行會馬上結束函數的運行
而每次執行到yield語句並返回一個值以後會暫停或掛起後面的代碼的執行,下次經過生成器對象的__next__()、for循環或其餘方式索要數據時恢復執行
生成器具備惰性求值的特色
生成器運行順序:
生成器問題注意1:
1 def generator_func(): #生成器函數
2 print(123) 3 yield 'aaa'
4 print(456) 5 yield 'bbb'
6 ret_1 = generator_func().__next__() 7 print(ret_1) 8 ret_2 = generator_func().__next__() 9 print(ret_2) 10 # 輸出結果:
11 # 123
12 # aaa
13 # 123
14 # aaa
15 def generator_func(): #生成器函數
16 print(123) 17 yield 'aaa'
18 print(456) 19 yield 'bbb'
20 generate_1 = generator_func() 21 ret_1 = generate_1.__next__() 22 print(ret_1) 23 ret_2 = generate_1.__next__() 24 print(ret_2) 25 # 輸出結果:
26 # 123
27 # aaa
28 # 456
29 # bbb
第6行和第8行至關於建立了兩個生成器,第20行建立了一個生成器,21行和23行都用的是第20行建立的生成器,因此輸出結果不同
生成器問題注意2:
for循環完了以後生成器數據就取完了,再繼續print數據的話,就會報錯,由於沒有數據能夠讀了。
一個函數有兩個以上的yield,纔算一個必要的生成器,若是隻有一個yield,那還不如老老實實的去寫return
生成器實例:
需求:寫一個實時監控文件輸入的內容,並將輸入內容返回的函數
1 def tail(filename): 2 f = open(filename,encoding='utf-8') 3 f.seek(0,2) 4 while True: 5 line = f.readline() 6 if not line:continue
7 yield line 8 tail_g = tail('file_1') 9 for line in tail_g:print(line,end='')
生成器send用法:
1.send和next工做的起止位置是徹底相同的
2.send能夠把一個值做爲信號量傳遞到函數中去
3.在生成器執行伊始,只能先用next
4.只要用send傳遞參數的時候,必須在生成器中還有一個未被返回的yield
1 def average_func(): 2 total = 0 3 count = 0 4 average = 0 5 while True: 6 value = yield average 7 total += value 8 count += 1
9 average = total/count 10 g = average_func() 11 print(g.__next__()) 12 print(g.send(30)) 13 print(g.send(20))
代碼解釋:
裝飾器生成激活函數裝置:
1 def wrapper(func): 2 def inner(*args,**kwargs): 3 g = func(*args,**kwargs) 4 g.__next__() 5 return g 6 return inner 7 @wrapper 8 def average_func(): 9 total = 0 10 count = 0 11 average = 0 12 while True: 13 value = yield average 14 total += value 15 count += 1
16 average = total/count 17 g = average_func() 18 print(g.send(30))
利用函數裝飾器寫了一個函數激活裝置,就不用在18行以前的send前使用 next 了,next 在第4行已經實現了。