无码人妻A片一区二区三区_18禁裸乳无遮挡啪啪无码免费_91精品亚?影视在线?看_人人妻人人爽人人澡AV_国产精品人妻一区二区三区四区_午夜免费影视

中培偉業IT資訊頻道
您現在的位置:首頁 > IT資訊 > 軟件研發 > Python核心編程的四大神器是什么?

Python核心編程的四大神器是什么?

2020-07-31 14:51:46 | 來源:中培企業IT培訓網

可能很多人都不知道Python核心編程是什么,其實《Python核心編程》(第二版)是一本書,2008年人民郵電出版社出版的圖書。這本書非常適合初學者學習,不過讓人印象深刻的還是Python核心編程的四大神器。因此有人會問Python核心編程的四大神器是什么?其實Python核心編程是迭代器、生成器 、閉包以及裝飾器。下面是詳細介紹。

  生成器

生成器是生成一個值的特殊函數,它具有這樣的特點:第一次執行該函數時,先從頭按順序執行,在碰到yield關鍵字時該函數會暫停執行該函數后續的代碼,并且返回一個值;在下一次調用該函數執行時,程序將從上一次暫停的位置繼續往下執行。

通過一個例子來理解生成器的執行過程。求1-10的所有整數的立方并將結果打印輸出,正常使用列表的實現如下:

def lifang_ls():

"""求1-10所用整數的立方數-列表方式實現"""

ls = []

for i in range(1,11):

result = i ** 3

ls.append(result)

print(ls)

if __name__ == '__main__':

lifang_ls()

輸出結果如下:

當數據量很少時,可以很快得到結果。但是如果范圍擴大到10000甚至是100000000,就會發現程序執行時間會變長,變卡,甚至有可能會因超出內存空間而出現程序崩潰的現象。這是因為當數據量變得非常大的時候,內存需要開辟很大的空間去存儲這些數據,內存都被吃了,自然會變慢變卡。使用生成器就能解決這個問題。

對于上述同一個問題用生成器實現如下,將范圍擴大到1-10000000:

def lifang_generate():

"""求1-10000000所用整數的立方數-生成器方式實現"""

for i in range(1,10000001):

result = i ** 3

yield resultif __name__ == '__main__':

G = lifang_generate()

執行效果如下:

可以看到沒有任何的結果輸出,這說明程序已經可以順利執行。對于迭代器來講需要用next()方法來獲取值,修改主函數為以下情況可以打印輸出前4個整數的立方數:

if __name__ == '__main__':

G = lifang_generate()

print(next(G))

print(next(G))

print(next(G))

print(next(G))

輸出結果如下:

到此可以看到,生成器生成的值需要使用next()方法一個一個的取,它不會一次性生成所有的計算結果,只有在取值時才調用,這時程序會返回計算的一個值且程序暫停;下一次取值時從上一次中斷了的地方繼續往下執行。

以取出前3個值為例,下圖為生成器代碼解析圖:

圖解:Python解釋器從上往下解釋代碼,首先是函數定義,這時在計算機內存開辟了一片空間來存儲這個函數,函數沒有被執行,繼續往下解釋;到了主函數部分,首先執行藍色箭頭1,接著往下執行到藍色箭頭2第一次調用生成器取值,此時生成器函數lifang_generate()開始執行,執行到生成器函數lifang_generate()的藍色箭頭2碰到yield關鍵字,這時候生成器函數暫停往下執行并且將result的結果返回,由于是第一次執行,因此result存儲著1的立方的值,此時將1返回,第54行代碼print(first)將結果打印輸出。

主函數中程序接著往下執行到藍色箭頭3,生成器函數lifang_generate()第二次被調用,與第一次不同,第二次從上一次(也就是第一次)暫停的位置繼續往下執行,上一次停在了yield處,因此藍色箭頭3所作的事情就是執行yield后面的語句,也就是第48行print('end'),執行完成之后因for循環條件滿足,程序像第一次執行那樣,執行到yield處暫停并返回一個值,此時返回的是2的立方數,在第57行打印輸出8。

第三次調用(藍色箭頭4)與第二次類似,在理清了執行過程之后,程序執行結果如下:

  迭代器

這里先拋出兩個概念:可迭代對象、迭代器。

凡是可以通過for循環遍歷其中的元素的對象,都是可迭代對象;之前學習得組合數據類型list(列表)、tuple(元組)、dict(字典)、集合(set)等,上一小節介紹得生成器也可以使用for循環來遍歷,因此,生成器也是迭代器,但迭代器不一定就是生成器,例如組合數據類型。

凡是可以通過next訪問取值得對象均為迭代器,生成器就是一種迭代器??梢钥吹?,生成器不僅可以用for循環來獲取值,還可以通過next()來獲取。

Python中有一個庫collections,通過該庫的Iterable方法來判斷一個對象是否是可迭代對象;如果返回值為True則說明該對象為可迭代的,返回值為False則說明該對象為不可迭代。用Iterator方法來判斷一個對象是否是迭代器,根據返回值來判斷是否為迭代器。

使用Iterable分別判斷列表,字典,字符串以及一個整數類型是否是可迭代對象的代碼如下:

from collections import Iterable

def isiterable():

"""分別判斷列表,字典,字符串100,整形100是不是可迭代對象"""

ls = isinstance([],Iterable)

dic = isinstance({},Iterable)

strs = isinstance('100',Iterable)

ints = isinstance(100,Iterable)

print('輸出True表示可迭代,False表示不可迭代

ls為{},dic為{},strs為{},ints為{}'.format(ls,dic,strs,ints))

def main():

isiterable()

if __name__ == '__main__':

main()

執行的輸出結果如下:

使用Iterator判斷一個對象是否是迭代器的代碼如下,與判斷是否為可迭代對象類似:

from collections import Iterable,Iterator

def print_num():

"""定義一個產生斐波那契數列的生成器"""

a,b = 0,1

for i in range(1,10):

yield b

a,b = b,a + b

def isiterator():

"""分別判斷列表,字典、生成器是否為迭代器"""

ls_ret = isinstance([],Iterator)

dict_ret = isinstance({},Iterator)

genarate_ret = isinstance((x * 2 for i in range(10)),Iterator)

print_num_ret = isinstance(print_num(),Iterator)

print('輸出True表示該對象為迭代器,False表示該對象不是迭代器

ls輸出為{},dict輸出為{},genarate輸出為{},print_num輸出為

{}'.format(ls_ret,dict_ret,genarate_ret,print_num_ret))

def main():

isiterator()

if __name__ == '__main__':

main()

輸出的結果如下:

組合數據類型不是迭代器,但是屬于可迭代對象,可以通過iter()函數將其轉換位迭代器,這樣就可以使用next方法來獲取對象各個元素的值,代碼如下:

from collections import Iterable,Iterator

def trans_to_iterator():

"""使用iter()將可迭代類型-列表轉換為迭代器"""

ls = [2,4,6,8,10]

ls_ierator = iter(ls)

ls_ierator_is = isinstance(ls_ierator,Iterator)

print('轉換后的返回值為{},使用next取出的第一個元素的值為

{}'.format(ls_ierator_is,next(ls_ierator)))

def main():

trans_to_iterator()

if __name__ == '__main__':

main()

輸出結果為:

閉包

內部函數對外部函數變量的引用,則將該函數與用到的變量稱為閉包。以下為閉包的例子:

def func(num):

print('start')

def func_in():

"""閉包內容"""

new_num = num ** 3

print(new_num)

return func_in

if __name__ == '__main__':

ret = func(10)

ret()

理解閉包是理解裝飾器的前提,同樣通過一張圖來理解閉包的執行過程:

圖解:Python解釋器從上往下解釋代碼,首先定義一個函數,func指向了該函數(紅箭頭所示);接著到主函數執行第14行代碼 ret = func(10),此時先執行賦值號“=”右邊的內容,這里調用了函數func()并傳入10這個實參,函數func()代碼開始執行,先是打印輸出“start”,接著定義了一個函數func_in(),func_in指向了該函數,函數沒有被調用,程序接著往下執行,return func_in 將函數的引用返回,第14行代碼用ret接收了這個返回值,到此ret就指向了func_in所指向的函數體(綠箭頭所示)。最后執行ret所指的函數。這就是閉包的整個過程,func_in()函數以及該函數內用到的變量num就稱為閉包。

  裝飾器

代碼的編寫需要遵循封閉開放原則,封閉是指對于已有的功能代碼實現不允許隨意進行修改,開放是指能夠對已有的功能進行擴展。例如一款手游,現在已經能夠實現現有的游戲模式,但隨著外部環境的變化發展(市場競爭,用戶體驗等),現有的游戲模式已經不能滿足用戶的需求了。為了留住用戶,需要加入更多的玩法來保持用戶對該款游戲的新鮮感,于是開發方在原來游戲的基礎上又開發了好幾種游戲模式。像這樣,新的游戲版本既增加了先的游戲模式,又保留了原有的游戲模式,體現了封閉開放的原則。 裝飾器的作用就是在不改變原來代碼的基礎上,在原來的功能上進行拓展,保證開發的效率以及代碼的穩定性。 打印輸出九九乘法表可以通過以下代碼實現:

def func_1():

"""打印輸出九九乘法表"""

for i in range(1,10):

for j in range(1,i + 1):

result = i * j

print('{}*{}={}'.format(i,j,result),end=' ')

print('')

if __name__ == '__main__':

func_1()

輸出結果如下:

假如現在需要實現一個功能,在不修改func_1函數代碼的前提下,在九九乘法表前增加一個表頭說明,在乘法表最后也增加一個說明。下面的代碼實現了裝飾器的功能:

def shuoming(func):

def shuoming_in():

print('以下為九九乘法表:')

func()

print('以上為九九乘法表')

return shuoming_in

def func_1():

"""打印輸出九九乘法表"""

for i in range(1,10):

for j in range(1,i + 1):

result = i * j

print('{}*{}={}'.format(i,j,result),end=' ')

print('')

if __name__ == '__main__':

func_1 = shuoming(func_1)

func_1()

輸出結果如下:

  可以看到func_1函數的代碼沒有任何修改,還實現了問題提出的要求,這其中的核心就在于最后兩行代碼。通過下圖來理解裝飾器執行的過程:

圖解:跟之前一樣,Python解釋器自上往下解釋代碼,遇到定義函數的代碼不用管,因為沒有調用函數是不會執行的;這樣直接就來到了第22行代碼中,程序先執行賦值號“=”右邊的代碼,shuoming(func_1)調用了之前定義的函數,并傳入了func_1實參,程序轉到shuoming(func)執行,形參func接收實參func_1,此時func也指向了func_1所指向的函數(如圖中分界線上方白色方框內的藍箭頭所示);在shuoming()函數中代碼繼續往下走,在shuoming()函數內容又定義了一個shuoming_in()函數(如圖中分界線上方白色方框內的藍色方框所示),接著往下,將shuoming_in()函數的引用返回,至此shuoming()函數執行完畢,程序回到第22行代碼執行,shuoming()函數的返回值被func_1接收,此時,func_1不在指向原來的函數,轉成指向shuoming_in所指向的函數(如圖中分界線下方白色方框內的黃色箭頭)。最后調用func_1所指向的函數,也就是shuoming_in()函數,shuoming_in()函數內的func指向了原來func_1()所指的函數(也就是生成九九乘法表的函數),因此程序最終的結果就在九九乘法表前后各加了一個說明性字符串。

以上為裝飾器的執行過程,但是以上裝飾寫法不夠簡潔,大多數情況下采取以下寫法,輸出結果是一樣的:

def shuoming(func):

def shuoming_in():

print('以下為九九乘法表:')

func()

print('以上為九九乘法表')

return shuoming_in

"""@shuoming相當于func_1 = shuoming(fucn_1)"""

@shuoming

def func_1():

"""打印輸出九九乘法表"""

for i in range(1,10):

for j in range(1,i + 1):

result = i * j

print('{}*{}={}'.format(i,j,result),end=' ')

print('')

if __name__ == '__main__':

"""直接調用func_1即可完成裝飾"""

func_1()

有時候有些被裝飾的函數可能有以下幾種情況:存在或不存在參數,有返回值或沒有返回值,參數可能定長或不定長等等,為了通用性,與爬蟲的請求代碼一樣,裝飾器有著通用的寫法:

def tongyong(func):

def tongyong_in(*args,**kwargs):

ret = func(*args,**kwargs)

return ret

return tongyong_in

使用這個裝飾器裝飾九九乘法表一樣可以正常輸出,如果需要特定的裝飾效果,修改這個通用代碼即可。

好了,關于Python核心編程的四大神器是什么相信大家已經知道了吧,想了解更多關于Python核心編程的信息,請繼續關注中培偉業。

主站蜘蛛池模板: 日本爽快片视频 | 91性高潮久久久久久久久 | 粉嫩av一区二区三区免费看 | 欧美亚洲精品中文字幕 | 尤物国精品午夜福利视频 | 日本一区二区小视频 | 日本欧美大码A在线观看 | 午夜dj影院| 国产精品久久久久久亚洲影视公司 | 国产黄a三级三级三级70年后 | 7mav视频| 少妇被粗大的猛烈进出动态图片 | 亚洲精品久久久久久久久久吃药 | 亚洲精品乱码久久久久久按摩观 | 国产精品久久久久久亚洲影视 | 久久久久99精品国产片 | 日本国产亚洲 | 欧美一级特黄乱妇高清视频 | 好男人www在线社区 久久精品视频3 | 一区二区三区无码视频免费福利 | 啪啪网站免费 | 日本乱码一区二区三区高清在线观看 | 91红桃视频 | 国产OO后高中生在线视频 | 片多多影视剧免费观看在线观看 | 野花香视频在线观看最新 | 国产精品一区三区在线观看 | 天天综合视频 | 91看篇 | 丰满人妻熟妇乱又伦精品视 | 亚洲av永久无码精品网站mmd | 久久精品免费在线观看 | 人妻无码中文字幕永久有效视频 | 久久久久人妻一区精品性色AV | 国产精品一线二线三线 | 欧美裸体xxxx极品少妇软件 | 卡通动漫av| a在线视频| 日日噜噜夜夜狠狠久久av小说 | 国产精品男人影院在线播放 | 国产精品美女久久久 |