在學(xué)習(xí)python中荆责,剛開始沒重視閉包函數(shù)和裝飾器滥比,后來發(fā)現(xiàn)裝飾器非常重要,在這重新梳理一下做院,也讓自己再加深下印象盲泛。
一、函數(shù)閉包:? ?
什么是閉包函數(shù)键耕,其實就是必須滿足以下三點的函數(shù):
?1寺滚,必須要有一個內(nèi)嵌函數(shù)? ??
2,嵌套函數(shù)必須引用封閉函數(shù)中的變量? ?
?3屈雄,閉包函數(shù)必須要返回內(nèi)嵌函數(shù)
比如求一個y = kx +b;這種求一次函數(shù)直線上任意一個x值的y值村视;
傳統(tǒng)函數(shù)定義可能如下:
def line(k,x,b):
????????return k*x+b
res = line(1,2,3)
print(res)
# 5
這種函數(shù)當(dāng)然可是實現(xiàn),但是就是輸入形參太多酒奶,而且蚁孔,加入一條直線固定,只需要輸入一個x即可:所以可是重新定義一個閉包函數(shù)惋嚎,如下:
def lineOut(k,b):
????????def line(x):
????????????????return k*x+b
????????return line
line = lineOut(1,2)
res = line(3)
print(res)
# 5
這樣的話杠氢,就可以只調(diào)用line這個函數(shù)返回函數(shù),進(jìn)行直傳一個參數(shù)就可以了另伍。
二鼻百、閉包函數(shù)的用途:? ?
?1,裝飾器:其中一個應(yīng)用寫了一個登錄功能摆尝,需要統(tǒng)計這個功能執(zhí)行花費的時間温艇,可以使用裝飾器實現(xiàn);還有可以實現(xiàn)打印日志? ?
?2,實現(xiàn)面向?qū)ο蠖楣热鏙avaScript中使用閉包函數(shù)實現(xiàn)面向?qū)ο蟮墓δ苌装瑢傩赞k法? ??
3,實現(xiàn)單利模式臼朗,單利類邻寿,一個類只有一個實例蝎土。'''
下面有這個實例是定義一個求和函數(shù)视哑,然后用閉包函數(shù)調(diào)用绣否,并判斷條件是否滿足是整型,滿足條件就執(zhí)行求和函數(shù)挡毅,本身求和函數(shù)代碼不做任何修改蒜撮,更加模塊化,更方便維護和調(diào)用跪呈,耦合性降低不少段磨,具體代碼如下:
def mySum(*args):
????????return sum(args)
def dec(fun):
????????def inDec(*args):
????????????????if len(args) ==0:
????????????????????????return 0
? ? ? ? ????????for i in args:
????????????????????????if not isinstance(i,int):
????????????????????????????????return 0
? ? ? ? ? ? ? ? ?return fun(*args)
????????return inDec
res = dec(mySum)
# res1 = res(1,2,3,89)
# res1 = res("99",9)
res1 = res()
print(res1)
三、裝飾器:
其實上面那個求和函數(shù)已經(jīng)用到了裝飾器的作用耗绿,就是執(zhí)行指定函數(shù)時還能執(zhí)行其他操作苹支,并不影響原函數(shù)的代碼,裝飾器本質(zhì)就是一個函數(shù)误阻,但是它有特殊作用债蜜,它用來裝飾別的函數(shù),給其他函數(shù)附加新的功能
? ? 特點究反,原則:? ? ? ?
?1寻定,不能修改被裝飾的函數(shù)的源代碼? ? ? ??
2,不能改變裝飾器函數(shù)的調(diào)用方式'''
裝飾器和閉包函數(shù)最大的區(qū)別是在于它的引用方式精耐,使用"@"寫在裝飾器函數(shù)之前狼速,并整體放在需要裝飾的函數(shù)前面一行,這樣在調(diào)用功能函數(shù)時卦停,系統(tǒng)就會自動執(zhí)行裝飾器函數(shù)向胡,并且執(zhí)行返回的嵌套函數(shù),說白了就是省略了之前自己手動調(diào)用返回嵌套函數(shù)的步驟惊完,并且在嵌套函數(shù)內(nèi)部僵芹,調(diào)用了功能函數(shù)。其中有幾點需要強調(diào):
1专执,裝飾器函數(shù)必須要有形參淮捆,且傳入的是函數(shù)名;
2本股,嵌套函數(shù)會自動執(zhí)行攀痊,且會自動把功能的實參復(fù)制一份到自己的實參列表,并且在執(zhí)行其他功能外拄显,會調(diào)用功能函數(shù)苟径;
3,裝飾器給人感覺是先執(zhí)行裝飾器函數(shù)功能躬审,后執(zhí)行功能函數(shù)棘街,其實不然蟆盐,它是在裝飾器內(nèi)部及已經(jīng)調(diào)用功能函數(shù),所以調(diào)用功能函數(shù)時遭殉,其實是值執(zhí)行裝飾器函數(shù)石挂,只不過是執(zhí)行中會調(diào)用功能函數(shù);(不知道大家有沒有看懂险污。痹愚。。蛔糯。拯腮。∫响看下面代碼动壤,自己運行,就能理解)
4淮逻,最后注意裝飾器函數(shù)的返回值設(shè)計
實例一:測試函數(shù)執(zhí)行順序
def log(func):
????????def wrapper(*args,**kwargs):
????????????????print("begin call %s"%func.__name__)
????????????????tem = func(*args,**kwargs)
????????????????print("after call %s"%func.__name__)
????????????????return tem
????????return wrapper
?@log
def new():
????????print("正在執(zhí)行琼懊。。弦蹂。肩碟。")
new = new()
print(new)
實例二:#定義一個裝飾器,用來測試一個函數(shù)的執(zhí)行時間
import os
import time
#定義一個裝飾器凸椿,用來測試一個函數(shù)的執(zhí)行時間
def getTime(func):
????????def wrapper(*args,**kwargs):
????????????????startTime = time.time()
????????????????func(*args, **kwargs)
????????????????endTime = time.time()
????????????????print("%s執(zhí)行了%s秒"%(func.__name__,endTime-startTime))
????????return wrapper
@getTime
def f1():
????????print("正在執(zhí)行削祈。。脑漫。髓抑。。优幸。吨拍。")
????????time.sleep(1)
f1()
實例三:高階裝飾器,其實就是閉包函數(shù)里面還是一個閉包函數(shù)网杆,就是高階裝飾器:
def outLog(text):
????????def log(func):
????????????????def wrapper(*args,**kwargs):
????????????????????????print(text)
? ? ? ? ? ? ? ? ? ? ? ? print("%s執(zhí)行了"%func.__name__)
????????????????????????res = func(*args,**kwargs)
????????????????????????return res
? ? ? ? ? ? ? ?return wrapper
? ? ? ? ?return log
@outLog("這是打印的text")
def f3(x,y):
????????return x+y
res = f3(1,898)
print(res)