python中的生成器、迭代器、裝飾器詳解
一、裝飾器
由于一個函數(shù)能實(shí)現(xiàn)一種功能,現(xiàn)在想要在不改變其代碼的情況下,讓這個函數(shù)進(jìn)化一下,即能保持原來的功能,還能有新的"技能",怎么辦?
現(xiàn)已經(jīng)存在一個自定義的函數(shù)func1
def func1(): print('hello,world!')
讓func1進(jìn)化一下:(繼承func1之前的所有功能,而且還有新的‘技能’)
效果和下面定義的函數(shù)func2效果是一樣的
def func2(): func1() #調(diào)用func1,即可保持func1這一函數(shù)的所有的功能都被這個新的函數(shù)繼承下來 print('hello,boy!') #添加的新功能,相當(dāng)于func1這一函數(shù)學(xué)到的新技能
但是,func2是一個新的函數(shù),已經(jīng)完全改頭換面了,雖然有一部分是能實(shí)現(xiàn)func1的功能,但并不是func1的進(jìn)化型,所以當(dāng)我們還想用調(diào)用func1這個函數(shù)的調(diào)用方法調(diào)用的時候,并不能調(diào)用func2.
當(dāng)函數(shù)不進(jìn)行調(diào)用時候,可以將這個函數(shù)當(dāng)成一個變量進(jìn)行對待。所以,如果把func2這個函數(shù)的內(nèi)存地址賦給func1,然后調(diào)用func1,那么就能用func1這個名字,調(diào)用func2這個函數(shù),也就實(shí)現(xiàn)了func1這個函數(shù)的進(jìn)化。
所以,如果定義如下一個可以實(shí)現(xiàn)上述功能的函數(shù)deco,deco這個函數(shù)就要完成以下的兩件事情:
1.讓func2這個函數(shù)的內(nèi)存地址出現(xiàn),即:定義func2這個函數(shù)
2.在其執(zhí)行之后能夠,拿到func2的內(nèi)存地址,即把func2的內(nèi)存地址作為返回值返回
def deco(func1): def func2(): func1() #調(diào)用func1,即可保持func1這一函數(shù)的所有的功能都被這個新的函數(shù)繼承下來 print('hello,boy!') #添加的新功能,相當(dāng)于func1這一函數(shù)學(xué)到的新技能 return func2
完成上述deco函數(shù)的定義之后,當(dāng)執(zhí)行deco這個函數(shù)之后,其執(zhí)行結(jié)果,就是func2的內(nèi)存地址。
接下來,將這個內(nèi)存地址賦值給func1這個變量之后,再對func1進(jìn)行調(diào)用,就可以完成對函數(shù)func1的"進(jìn)化"(即:在不改變func1的代碼,還賦予了其新的功能)
func1 = deco(func1) func1()
上述的過程可以用以下的代碼進(jìn)行實(shí)現(xiàn):
def deco(func1): def func2(): func1() #調(diào)用func1,即可保持func1這一函數(shù)的所有的功能都被這個新的函數(shù)繼承下來 print('hello,boy!') #添加的新功能,相當(dāng)于func1這一函數(shù)學(xué)到的新技能 return func2 def func1(): print('hello,world!') func1 = deco(func1) func1()
其中,deco這個函數(shù)就是所謂的裝飾器
(裝飾器:在不改變源代碼和調(diào)用方式的基礎(chǔ)之上給函數(shù)增加新的功能)
將上述代碼進(jìn)行優(yōu)化之后就有了下面的代碼:
def deco(func1): def func2(): func1() #調(diào)用func1,即可保持func1這一函數(shù)的所有的功能都被這個新的函數(shù)繼承下來 print('hello,boy!') #添加的新功能,相當(dāng)于func1這一函數(shù)學(xué)到的新技能 return func2 @deco #效果等同于func1=deco(func1) def func1(): print('hello,world!') func1()
1.1含參數(shù)的裝飾器:
def deco(func): def wrapper(username,password): if username == 'root' and password == 'root': func(username,password) else: print('用戶名或密碼錯誤') return wrapper @deco def baidu_index(username,password): print('welcome to 百度') baidu_index('root','root')
由于定義的函數(shù)baidu_index,必須要傳遞參數(shù),所以裝飾器內(nèi)部定義的函數(shù)wrapper也需要定義形參,wrapper函數(shù)內(nèi)部調(diào)用函數(shù)時,也需要有參數(shù)?。?/p>
1.2多層裝飾器
將裝飾器1看成一個整體,在這個裝飾器上在添加一個裝飾器2,就能實(shí)現(xiàn)..........
例如:
def deco1(deco): print('你好不好?') def deco(func): def func2(): print('你不好!') func() return func2 return deco @deco1 def deco(func): def func2(): print('你不好!') func() return func2 @deco def func1(): print('你好!') func1()
二、迭代器:
1.什么是迭代?
1.迭代是一個重復(fù)的過程,即每一次重復(fù)為一次迭代,
2.并且每次迭代的結(jié)果都是下一次迭代的初始值
例如:
l = [1,2,3] count=0 while count<len(l): #首先是重復(fù)動作,其次上一次的結(jié)果是下一次的初始值,因此,是迭代 print(l[count]) count+=1
2.什么是迭代器?為何要有迭代器?
對于序列類型:字符串、列表、元組,我們可以使用索引的方式迭代取出其包含的元素。但對于字典、集合、文件等類型是沒有索引的,若還想取出其內(nèi)部包含的元素,則必須找出一種不依賴于索引的迭代方式,這就是迭代器。
3.什么叫做迭代器對象?
obj有.__iter__和.__next__方法的叫做迭代器對象
總結(jié):迭代器對象一定是可迭代對象,而可迭代對象不一定是迭代器對象
4.for的作用:
1.把可迭代對象變成迭代器對象
2.過濾錯誤信息
l1 = [1,2,3] for i in l1: #iter(l1) print(i)
三、生成器
1.什么是生成器?
只要函數(shù)里有yield關(guān)鍵字,那么函數(shù)名()得到的結(jié)果就是生成器,生成器就是迭代器,并且不會執(zhí)行函數(shù)內(nèi)部代碼
2.return和yield用法十分類似,但是也有區(qū)別,區(qū)別在于:return只能返回一個值,而yield可以返回多個值
3.生成器優(yōu)點(diǎn):
同一時間只存儲一個值,節(jié)省內(nèi)存空間
4.生成器的缺點(diǎn):
只能向后取值,不能往前取值
def test(): for i in range(100): yield i res = test() for k in res: print(k)
四、總結(jié)
迭代器
迭代是Python最強(qiáng)大的功能之一,是訪問集合元素的一種方式;迭代器是一個可以記住遍歷的位置的對象;迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退;迭代器有兩個基本的方法:iter()和next();字符串,列表或元組對象都可用于創(chuàng)建迭代器:
迭代器python實(shí)例
生成器
在 Python 中,使用了 yield 的函數(shù)被稱為生成器;跟普通函數(shù)不同的是,生成器是一個返回迭代器的函數(shù),只能用于迭代操作,更簡單點(diǎn)理解生成器就是一個迭代器;在調(diào)用生成器運(yùn)行的過程中,每次遇到 yield 時函數(shù)會暫停并保存當(dāng)前所有的運(yùn)行信息,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當(dāng)前位置繼續(xù)運(yùn)行;調(diào)用一個生成器函數(shù),返回的是一個迭代器對象。
使用生成器生成斐波那些數(shù)列
裝飾器
裝飾器:在不改變原函數(shù)的基礎(chǔ)上,對函數(shù)執(zhí)行前后進(jìn)行自定義操作。把目標(biāo)函數(shù)作為參數(shù)傳給裝飾器函數(shù),裝飾器函數(shù)執(zhí)行過程中,執(zhí)行目標(biāo)函數(shù),達(dá)到在目標(biāo)函數(shù)運(yùn)行前后進(jìn)行自定義操作的目的。
應(yīng)用場景:如記錄函數(shù)運(yùn)行時間;flask里的路由、before_request;django中的緩存、用戶登錄等。
使用裝飾器記錄函數(shù)運(yùn)行時間
裝飾器在實(shí)現(xiàn)的時候,被裝飾后的函數(shù)其實(shí)已經(jīng)是另外一個函數(shù)了(函數(shù)名等函數(shù)屬性會發(fā)生改變),為了不影響,Python的functools包中提供了一個叫wraps的裝飾器來消除這樣的副作用。寫一個裝飾器的時候,最好在實(shí)現(xiàn)之前加上functools的wrap,它能保留原有函數(shù)的名稱和文檔字符串。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python實(shí)現(xiàn)計算對象的內(nèi)存大小示例
這篇文章主要介紹了Python實(shí)現(xiàn)計算對象的內(nèi)存大小,結(jié)合實(shí)例形式分析了Python使用sys.getsizeof與遞歸算法計算對象占用內(nèi)存的相關(guān)操作技巧,需要的朋友可以參考下2019-07-07Python?range函數(shù)生成一系列連續(xù)整數(shù)的內(nèi)部機(jī)制解析
這篇文章主要為大家介紹了Python?range函數(shù)生成一系列連續(xù)整數(shù)的內(nèi)部機(jī)制解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12Python 點(diǎn)擊指定位置驗(yàn)證碼破解的實(shí)現(xiàn)代碼
這篇文章主要介紹了Python 點(diǎn)擊指定位置驗(yàn)證碼破解的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09python UIAutomator2使用超詳細(xì)教程
這篇文章主要介紹了python UIAutomator2使用超詳細(xì)教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02利用Python中unittest實(shí)現(xiàn)簡單的單元測試實(shí)例詳解
如果項(xiàng)目復(fù)雜,進(jìn)行單元測試是保證降低出錯率的好方法,Python提供的unittest可以很方便的實(shí)現(xiàn)單元測試,從而可以替換掉繁瑣雜亂的main函數(shù)測試的方法,將測試用例、測試方法進(jìn)行統(tǒng)一的管理和維護(hù)。本文主要介紹了利用Python中unittest實(shí)現(xiàn)簡單的單元測試。2017-01-01從Pyspark UDF調(diào)用另一個自定義Python函數(shù)的方法步驟
PySpark,通常稱為Apache Spark的Python API,是為分布式數(shù)據(jù)處理而創(chuàng)建的,使用UDF,可以擴(kuò)展和定制 PySpark 的功能以滿足某些需求,在本文中,我們將學(xué)習(xí)如何從Pyspark UDF調(diào)用另一個自定義Python函數(shù),需要的朋友可以參考下2023-11-11