python05-Debug、函數裝飾器、迭代器、生成器

目錄:python

1、Debug操做閉包

2、函數的裝飾器app

3、迭代器函數

4、生成器spa

1、Debug操做:debug

程序出問題的時候能夠用debug來看一下代碼運行軌跡,而後找找問題在哪裏code

1.先給即將debug的代碼打上斷點:對象

 2.打完斷點以後右鍵點擊debug:blog

 3.而後依次點擊開始按鈕讓程序開始一步步運行:內存

2、函數的裝飾器:

定義:裝飾器爲其餘函數添加附加功能,本質上仍是一個函數

原則:①不修改被修飾函數的源代碼

      ②不修改被修飾函數的調用方式

有這樣一個函數: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)

圖示流程:

3、迭代器: 

可迭代協議:只要包括了"_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內部會將可迭代對象轉換成迭代器而已。

4、生成器:

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行已經實現了。

相關文章
相關標籤/搜索