python高級(jí)語(yǔ)法之閉包和裝飾器詳解
一、閉包
閉包的形成條件:
1.函數(shù)嵌套。
2.內(nèi)部函數(shù)使用了外部函數(shù)的變量或者參數(shù)。
3.外部函數(shù)返回了使用外 部變量的內(nèi)部函數(shù)。
二、一個(gè)簡(jiǎn)單的例子
def func_out(num1): def inner(num2): res = num1 + num2 print(res) return inner # a = func_out(10)(10) a = func_out(10) a(10)
閉包修改外部函數(shù)的變量:
在閉包內(nèi)修改外部函數(shù)的變量需要使用nonlocal關(guān)鍵字
def func_out(): # 外部函數(shù)的變量 num1 = 10 def func_inner(): # 在閉包內(nèi)修改外部函數(shù)的變量 nonlocal num1 num1 = 20 res = num1 +20 print(res) print("修改前的變量", num1) func_inner() print("修改后的變量", num1) return func_inner new_func = func_out() new_func()
三、裝飾器
3.1 簡(jiǎn)單裝飾器
裝飾器就是給已有函數(shù)增加額外功能的函數(shù),它本質(zhì)上就是一個(gè)閉包函數(shù),也就是說(shuō)也是一個(gè)函數(shù)嵌套。裝飾器的功能特點(diǎn):
1.不修改已有函數(shù)的源代碼
2.不修改已有函數(shù)的調(diào)用方式
3.給已有函數(shù)增加額外的功能
用戶(hù)在發(fā)表評(píng)論的時(shí)候需要驗(yàn)證用戶(hù)是否登錄,我們首先會(huì)想到去修改原來(lái)的函數(shù),在函數(shù)里面添加一些功能,但是在現(xiàn)在這分工合作的時(shí)代,這樣的修改很容易出現(xiàn)修改了祖?zhèn)鞯拇a后,函數(shù)出現(xiàn)問(wèn)題,也影響代碼的高效復(fù)用。為了能夠不重新修改原來(lái)的評(píng)論的代碼,實(shí)現(xiàn)高水平的代碼復(fù)用。
原本的函數(shù)及其調(diào)用:
def comment(): print("執(zhí)行祖?zhèn)鞔a.....") print("發(fā)表評(píng)論") # 調(diào)用評(píng)論功能 comment()
自己手寫(xiě)一個(gè)實(shí)現(xiàn)裝飾器功能的函數(shù)實(shí)現(xiàn)登錄驗(yàn)證:
def decorator(func): def inner(): print('正在驗(yàn)證登錄者身份...\n驗(yàn)證成功') func() return inner def comment(): print("執(zhí)行祖?zhèn)鞔a.....") print("發(fā)表評(píng)論") # 調(diào)用評(píng)論功能 comment = decorator(comment) comment()
輸入結(jié)果:
正在驗(yàn)證登錄者身份…
驗(yàn)證成功
執(zhí)行祖?zhèn)鞔a…
發(fā)表評(píng)論
3.1.1 使用裝飾器的語(yǔ)法糖
裝飾器的語(yǔ)法糖寫(xiě)法:@裝飾器名稱(chēng)
如例子可以改寫(xiě)為:
def decorator(func): def inner(): print('正在驗(yàn)證登錄者身份...\n驗(yàn)證成功') func() return inner @decorator def comment(): print("執(zhí)行祖?zhèn)鞔a.....") print("發(fā)表評(píng)論") # 調(diào)用函數(shù) comment()
運(yùn)行結(jié)果:
正在驗(yàn)證登錄者身份…
驗(yàn)證成功
執(zhí)行祖?zhèn)鞔a…
發(fā)表評(píng)論
3.1.2 裝飾器的執(zhí)行時(shí)機(jī)
先說(shuō)結(jié)論:在使用裝飾器語(yǔ)法糖時(shí),會(huì)先將該裝飾器函數(shù)執(zhí)行一遍。
def decorator(func): # 測(cè)試裝飾器的執(zhí)行時(shí)機(jī) print('--remark1----') def inner(): print('正在驗(yàn)證登錄者身份...\n驗(yàn)證成功') func() print('----remark2---') return inner @decorator def comment(): print("執(zhí)行祖?zhèn)鞔a.....") print("發(fā)表評(píng)論")
輸出結(jié)果:
–remark1----
----remark2—
3.2 通用裝飾器
裝飾的函數(shù)可能有參數(shù)傳遞,或者有返回值,上面寫(xiě)的例子中,如果依然用上面的方法及逆行裝飾器的裝飾將會(huì)出現(xiàn)問(wèn)題,那是否有一個(gè)通用的裝飾器能夠裝飾任意函數(shù)呢?
3.2.1 裝飾帶有參數(shù)的函數(shù)
def logging(fn): def inner(num1,num2): print('執(zhí)行了一次計(jì)算') fn(num1,num2) return inner # 使用裝飾器裝飾函數(shù) @logging def sum_num(a,b): result = a + b print(result) sum_num(1,2)
3.2.2. 裝飾帶有返回值的函數(shù):
def logging(fn): def inner(num1,num2): print('執(zhí)行了一次計(jì)算') result = fn(num1,num2) return result return inner # 使用裝飾器裝飾函數(shù) @logging def sum_num(a,b): result = a + b return result print(sum_num(1,2))
3.2.3 實(shí)現(xiàn)通用裝飾器
*args
: 用于接收元組參數(shù),可傳可不傳
**kwargs
: 用于接收字典類(lèi)型參數(shù),可傳可不傳
def logging(fn): def inner(*args, **kwargs): result = fn(*args, **kwargs) return result return inner @logging def sum_num(a,b): result = a + b return result
3.3 多個(gè)裝飾器的使用
多個(gè)裝飾器的過(guò)程:由內(nèi)到外的裝飾過(guò)程,先執(zhí)行內(nèi)部裝飾器,再執(zhí)行外部裝飾器。
原理剖析:content = make_div(make_p(content))
分步拆解:content = make_p(content), 內(nèi)部裝飾器完成content=make_p.inner, content = make_div(make_p.inner)
def make_div(func): print("make_div裝飾器執(zhí)行了") def inner(): # 在內(nèi)部函數(shù)對(duì)已有函數(shù)進(jìn)行裝飾 result = "<div>" + func() +"</div>" return result return inner def make_p(func): print("make_p裝飾器執(zhí)行了") def inner(): # 在內(nèi)部函數(shù)對(duì)已有函數(shù)進(jìn)行裝飾 result = "<p>" + func() +"</p>" return result return inner @make_div @make_p def content(): return "人生苦短,我用Python"
輸出:
make_p裝飾器執(zhí)行了
make_div裝飾器執(zhí)行了
<div><p>人生苦短,我用Python</p></div>
3.4 帶有參數(shù)的裝飾器
帶有參數(shù)的裝飾器時(shí)機(jī)上就是定義了一個(gè)函數(shù),讓函數(shù)接收參數(shù),再函數(shù)內(nèi)部返回該裝飾器。
如定義一個(gè)能夠判斷加減的裝飾器:
def return_decorator(flag): def decorator(func): def inner(a,b): if flag == '+': print("正在進(jìn)行加法運(yùn)算") elif flag == '-': print("正在進(jìn)行減法運(yùn)算") func(a,b) return inner return decorator @return_decorator('+') def add_num(a,b): print(a+b) add_num(1,5)
3.5 類(lèi)裝飾器
使用類(lèi)裝飾已有函數(shù)。
class MyDecorator(object): def __init__(self,func): self.__func = func # 實(shí)現(xiàn)__call__方法,讓對(duì)象變成可調(diào)用的對(duì)象, # 可調(diào)用的對(duì)象能夠像函數(shù)一樣被使用。 def __call__(self,*args,**kwargs): # 對(duì)已有參數(shù)進(jìn)行封裝 print('--正在進(jìn)行裝飾-----') self.__func() @MyDecorator def show(): print("hello") # 指向MyDecorator類(lèi)創(chuàng)建實(shí)例對(duì)象--> show()==> 對(duì)象() show()
輸出:
–正在進(jìn)行裝飾-----
hello
到此這篇關(guān)于python高級(jí)語(yǔ)法之閉包和裝飾器詳解的文章就介紹到這了,更多相關(guān)python閉包和裝飾器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
介紹Python的Django框架中的靜態(tài)資源管理器django-pipeline
這篇文章主要介紹了介紹Python的Django框架中的靜態(tài)資源管理器django-pipeline,django-pipeline是一個(gè)開(kāi)源項(xiàng)目,被用來(lái)處理css等靜態(tài)文件,需要的朋友可以參考下2015-04-04python中nan與inf轉(zhuǎn)為特定數(shù)字方法示例
這篇文章主要給大家介紹了將python中nan與inf轉(zhuǎn)為特定數(shù)字的方法,文中給出了詳細(xì)的示例代碼和運(yùn)行結(jié)果,對(duì)大家的理解和學(xué)習(xí)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-05-05分享5個(gè)短小精悍的Python趣味腳本,適合小白上手!
這篇文章主要給大家分享介紹了5個(gè)短小精悍的Python趣味腳本,非常適合小白上手,分別包含圖片尺寸縮小、pdf轉(zhuǎn)txt文檔、猜數(shù)字游戲、電池電量告警以及圖片添加水印等腳本,需要的朋友可以參考下2022-02-02Python中使用__new__實(shí)現(xiàn)單例模式并解析
單例模式是一個(gè)經(jīng)典設(shè)計(jì)模式,簡(jiǎn)要的說(shuō),一個(gè)類(lèi)的單例模式就是它只能被實(shí)例化一次,實(shí)例變量在第一次實(shí)例化時(shí)就已經(jīng)固定。 這篇文章主要介紹了Python中使用__new__實(shí)現(xiàn)單例模式并解析 ,需要的朋友可以參考下2019-06-06pytorch實(shí)現(xiàn)對(duì)輸入超過(guò)三通道的數(shù)據(jù)進(jìn)行訓(xùn)練
今天小編就為大家分享一篇pytorch實(shí)現(xiàn)對(duì)輸入超過(guò)三通道的數(shù)據(jù)進(jìn)行訓(xùn)練,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01基于python實(shí)現(xiàn)音樂(lè)播放器代碼實(shí)例
這篇文章主要介紹了基于python實(shí)現(xiàn)音樂(lè)播放器代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07