日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

函数闭包与装饰器

發布時間:2025/3/17 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 函数闭包与装饰器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
# 統計函數的執行時間 import time def cal(l):start_time=time.time() #加入1res=0for i in l:time.sleep(0.1)res+=istop_time = time.time() #加入2print('函數的運行時間是%s' %(stop_time-start_time))return res #如果函數是線上運行的,那修改源代碼違反開放封閉式原則。因為別的可能還在調用它。print(cal(range(100)))def index():passdef home():pass

一 什么是裝飾器

裝飾器即函數

裝飾即修飾,意指為其他函數添加新功能

裝飾器定義:本質就是函數,功能是為其他函數添加新功能

二 裝飾器需要遵循的原則

1.不修改被裝飾函數的源代碼(開放封閉原則)

2.為被裝飾函數添加新功能后,不修改被修飾函數的調用方式

三 實現裝飾器知識儲備

裝飾器=高階函數+函數嵌套+閉包

四 高階函數

高階函數定義:
1.函數接收的參數是一個函數名

2.函數的返回值是一個函數名

3.滿足上述條件任意一個,都可稱之為高階函數

#1、函數接收的參數是一個函數名:保證函數源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數名,為高階函數。func為函數的內存地址# print(func) #打印出來的是內存地址start_time=time.time()func() #直接運行foo函數stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數的返回值也是一個函數名,函數的調用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內存地址 # print(res) res() #函數直接就運行了#進一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數調用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調用方式 #多運行了一次,不合格 def timer(func): #參數為函數名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數添加任何功能。stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time))return func #返回值為函數名 foo=timer(foo) #賦給foo,執行了一遍 foo() #直接調用foo,又執行了一遍foo。只能改return ##結果: 來自foo 函數運行時間是 3.0001756482365 來自foo #多打印了一個 #高階函數沒辦法正常運行且順利添加新功能 #1、函數接收的參數是一個函數名:保證函數源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數名,為高階函數。func為函數的內存地址# print(func) #打印出來的是內存地址start_time=time.time()func() #直接運行foo函數stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數的返回值也是一個函數名,函數的調用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內存地址 # print(res) res() #函數直接就運行了#進一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數調用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調用方式 #多運行了一次,不合格 def timer(func): #參數為函數名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數添加任何功能。stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time))return func #返回值為函數名 foo=timer(foo) #賦給foo,執行了一遍 foo() #直接調用foo,又執行了一遍foo。只能改return ##結果: 來自foo 函數運行時間是 3.0001756482365 來自foo #多打印了一個 #高階函數沒辦法正常運行且順利添加新功能 #1、函數接收的參數是一個函數名:保證函數源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數名,為高階函數。func為函數的內存地址# print(func) #打印出來的是內存地址start_time=time.time()func() #直接運行foo函數stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數的返回值也是一個函數名,函數的調用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內存地址 # print(res) res() #函數直接就運行了#進一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數調用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調用方式 #多運行了一次,不合格 def timer(func): #參數為函數名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數添加任何功能。stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time))return func #返回值為函數名 foo=timer(foo) #賦給foo,執行了一遍 foo() #直接調用foo,又執行了一遍foo。只能改return ##結果: 來自foo 函數運行時間是 3.0001756482365 來自foo #多打印了一個 #高階函數沒辦法正常運行且順利添加新功能 #1、函數接收的參數是一個函數名:保證函數源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數名,為高階函數。func為函數的內存地址# print(func) #打印出來的是內存地址start_time=time.time()func() #直接運行foo函數stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數的返回值也是一個函數名,函數的調用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內存地址 # print(res) res() #函數直接就運行了#進一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數調用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調用方式 #多運行了一次,不合格 def timer(func): #參數為函數名start_time=time.time()func() #return func如果換到這里來,并沒有給原函數添加任何功能。stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time))return func #返回值為函數名 foo=timer(foo) #賦給foo,執行了一遍 foo() #直接調用foo,又執行了一遍foo。只能改return ##結果: 來自foo 函數運行時間是 3.0001756482365 來自foo #多打印了一個 #高階函數沒辦法正常運行且順利添加新功能 #1、函數接收的參數是一個函數名:保證函數源代碼不被修改 import time def foo():time.sleep(3)print('你好啊林師傅')def test(func): #test形參接收了函數名,為高階函數。func為函數的內存地址# print(func) #打印出來的是內存地址start_time=time.time()func() #直接運行foo函數stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time)) # foo() test(foo)# 2、高階函數的返回值也是一個函數名,函數的調用方式也不用修改了 def foo():print('from the foo') def test(func):return func res=test(foo) #從而func就是foo內存地址 # print(res) res() #函數直接就運行了#進一步取消res,就用原來的foo名字 foo=test(foo) # # print(res) foo() # 不改變函數調用方式#########整合版本1 import time def foo():time.sleep(3)print('來自foo')#不修改foo源代碼 #不修改foo調用方式 #多運行了一次,不合格 def timer(func): #參數為函數名start_time=time.time()func() stop_time = time.time()print('函數運行時間是 %s' % (stop_time-start_time))return func #返回值為函數名 foo=timer(foo) #賦給foo,執行了一遍 foo() #直接調用foo,又執行了一遍foo。只能改return ##結果: 來自foo 函數運行時間是 3.0001756482365 來自foo #多打印了一個 #高階函數沒辦法正常運行且順利添加新功能

#沒有修改被修飾函數的源代碼,也沒有修改被修飾函數的調用方式,但是也沒有為被修飾函數添加新功能
def timer(func):
start_time=time.time()
return func #return func如果換到這里來,并沒有給原函數添加任何功能。
stop_time = time.time()
print('函數運行時間是 %s' % (stop_time-start_time)

foo=timer(foo)
foo()

#高階函數應用1:把函數當做參數傳給高階函數 import time def foo():print('from the foo')def timmer(func):start_time=time.time()func()stop_time=time.time()print('函數%s 運行時間是%s' %(func,stop_time-start_time)) timmer(foo) #總結:我們確實為函數foo增加了foo運行時間的功能,但是foo原來的執行方式是foo(),現在我們需要調用高階函數timmer(foo),改變了函數的調用方式 #高階函數應用2:把函數名當做參數傳給高階函數,高階函數直接返回函數名 import time def foo():print('from the foo')def timmer(func):start_time=time.time()return funcstop_time=time.time()print('函數%s 運行時間是%s' %(func,stop_time-start_time)) foo=timmer(foo) foo() #總結:我們確實沒有改變foo的調用方式,但是我們也沒有為foo增加任何新功能

高階函數總結
1.函數接收的參數是一個函數名
  作用:在不修改函數源代碼的前提下,為函數添加新功能,
  不足:會改變函數的調用方式
2.函數的返回值是一個函數名
  作用:不修改函數的調用方式
  不足:不能添加新功能

五 函數嵌套

# 函數嵌套:在一個函數中重新定義一個新的函數 def foo():print('from foo')def test():passdef father(auth_type):# print('from father %s' %name)def son():# name='linhaifeng_1'# print('我的爸爸是%s' %name)def grandson():print('我的爺爺是%s' %auth_type) #在上上級找,在最外層傳,這里也能收到grandson() #運行函數# print(locals()) #打印當前層的局部變量:name,son函數也是 son() # father('linhaifeng') father('filedb')
六 閉包 1 '''2 閉包:在一個作用域里放入定義變量,相當于打了一個包3 '''4 def father(name):5 def son():6 # name='alex'7 print('我爸爸是 [%s]' %name)8 def grandson():9 # name='wupeiqi' 10 print('我爺爺是 [%s]' %name) 11 grandson() 12 son() 13 14 father('林海峰') #裝飾器實現
import
time def timmer(func): #func=testdef wrapper():# print(func)start_time=time.time()func() #就是在運行test()stop_time = time.time()print('運行時間是%s' %(stop_time-start_time))return wrapper@timmer #test=timmer(test) def test():time.sleep(3)print('test函數運行完畢') test()res=timmer(test) #返回的是wrapper的地址 res() #執行的是wrapper() test=timmer(test) #返回的是wrapper的地址 test() #執行的是wrapper() @timmer 就相當于 test=timmer(test)

七 無參裝飾器

#補充知識:用解壓的方式取出一個列表的最開頭和結尾 #比索引略微簡潔一些,有的時候適用 #例1: a,b,c='hel' >>>a 'h' >>>b 'e' >>>c 'l' #例2:a表示列表第一個,c表示最后一個 l=[0,2,3,445,67,8,9,92,2,1] >>>a.*_.c=l #下劃線表示中間所有元素的變量名,可以隨便起,*m也可以 >>>a '0' >>>c '1' #例3:取出頭尾兩個 >>>a,b.*_.c,d=l #對比索引:a,d=l[0],l[-1]

無參裝飾器=高級函數+函數嵌套

基本框架

1 #這就是一個實現一個裝飾器最基本的架子 2 def timer(func):      #func就相當于你輸入的test函數 3 def wrapper():
4      print(func)   #函數嵌套 4 func() 5 return wrapper

加上參數

1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper

加上功能

1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time)) 8 return wrapper

加上返回值

1 import time 2 def timer(func): 3 def wrapper(*args,**kwargs): 4 start_time=time.time() 5 res=func(*args,**kwargs) 6 stop_time=time.time() 7 print('函數[%s],運行時間是[%s]' %(func,stop_time-start_time)) 8 return res 9 return wrapper

使用裝飾器

1 def cal(array): 2 res=0 3 for i in array: 4 res+=i 5 return res 6 7 cal=timer(cal) 8 cal(range(10))

語法糖@

1 @timer #@timer就等同于cal=timer(cal) 2 def cal(array): 3 res=0 4 for i in array: 5 res+=i 6 return res 7 8 cal(range(10))

八 裝飾器應用示例

# 京東登錄(無參數) # 利用用戶列表,for循環來遍歷該字典 user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} #記錄下當前用戶的狀態#加上認證功能的裝飾器函數:參數、返回值 #登錄一次之后,不用每次都再輸。應該記錄下登錄一次的狀態(用一個全局變量來實現) def auth_func(func): #函數名def wrapper(*args,**kwargs):if auth_type == 'filedb': if current_dic['username'] and current_dic['login']:res = func(*args, **kwargs)return resusername=input('用戶名:').strip()passwd=input('密碼:').strip()for user_dic in user_list: #遍歷列表中所有記錄是否與輸入的名字密碼匹配if username == user_dic['name'] and passwd == user_dic['passwd']:current_dic['username']=username #記錄下登錄的狀態:拿的就是全局變量的引用current_dic['login']=Trueres = func(*args, **kwargs) #驗證成功了才可以直接運行函數return res #wrapper函數直接結束,不必再加break語句了else:print('用戶名或者密碼錯誤') #此else與for連用,不是循環一次后的if連用。列表中用戶名和密碼全for循環完畢了return wrapperreturn auth_func@auth def index(): #已經輸入正確用戶名及密碼了print('歡迎來到京東主頁')@authdef home(name):print('歡迎回家%s' %name) @authdef shopping_car(name):print('%s的購物車里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))print('before-->',current_dic) index() print('after--->',current_dic) home('產品經理') shopping_car('產品經理') user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ]current_user={'username':None,'login':False} def auth(auth_type='file'):def auth_deco(func):def wrapper(*args,**kwargs):if auth_type == 'file':if current_user['username'] and current_user['login']:res=func(*args,**kwargs)return resusername=input('用戶名: ').strip()passwd=input('密碼: ').strip()for index,user_dic in enumerate(user_list):if username == user_dic['name'] and passwd == user_dic['passwd']:current_user['username']=usernamecurrent_user['login']=Trueres=func(*args,**kwargs)return resbreakelse:print('用戶名或者密碼錯誤,重新登錄')elif auth_type == 'ldap':print('巴拉巴拉小魔仙')res=func(*args,**kwargs)return resreturn wrapperreturn auth_deco#auth(auth_type='file')就是在運行一個函數,然后返回auth_deco,所以@auth(auth_type='file') #就相當于@auth_deco,只不過現在,我們的auth_deco作為一個閉包的應用,外層的包auth給它留了一個auth_type='file'參數 @auth(auth_type='ldap') def index():print('歡迎來到主頁面')@auth(auth_type='ldap') def home():print('這里是你家')def shopping_car():print('查看購物車啊親')def order():print('查看訂單啊親')# print(user_list) index() # print(user_list) home()

?裝飾器運行流程

import time def timmer(func): #func=test1 第二步 # wrapper中參數數目不要寫死,用列表裝def wrapper(*args,**kwargs): #第五步 #test('linhaifeng',age=18) 元祖args=('linhaifeng') kwargs={'age':18}start_time=time.time() #第六步 res=func(*args,**kwargs) #第七步,接著去找test函數定義去了 就是在運行test() func(*('linhaifeng'),**{'age':18})#wrapper中怎么接收的就怎么傳給funcstop_time = time.time() #第十二步print('運行時間是%s' %(stop_time-start_time)) #第十三步return res ##第十四步 加入返回值,結束wrapperreturn wrapper #第三步 @timmer #test=timmer(test) #第一步:運行這個執行timmer函數,直接返回wrapper地址給test,然后到test()調用 def test(name,age): #第八步:對應wrapper中形參表也要加time.sleep(3) #第九步print('test函數運行完畢,名字是【%s】 年齡是【%s】' %(name,age)) #第十步return '這是test的返回值' #第十一步 test() #第四步,直接運行wrapper函數 # 京東登錄:auth函數中帶參數:數據庫的認證類型來源 # 帶參數的少用,不帶參數的更加常用 # 利用用戶列表,for循環來遍歷該字典 # 缺點1、認證來源:用戶列表應該從數據庫里取出來。寫死了數據庫 #(可以將user_list寫到文件當中便于增刪改。注意提取文件內容時都是得到字符串,用eval剝離出來轉化為字典) user_list=[{'name':'alex','passwd':'123'},{'name':'linhaifeng','passwd':'123'},{'name':'wupeiqi','passwd':'123'},{'name':'yuanhao','passwd':'123'}, ] current_dic={'username':None,'login':False} #記錄下當前用戶的狀態#加上認證功能的裝飾器函數:參數、返回值 #登錄一次之后,不用每次都再輸。應該記錄下登錄一次的狀態(用一個全局變量來實現) def auth(auth_type='filedb'):def auth_func(func): #函數名def wrapper(*args,**kwargs):print('認證類型是',auth_type) if auth_type == 'filedb': if current_dic['username'] and current_dic['login']:res = func(*args, **kwargs)return resusername=input('用戶名:').strip()passwd=input('密碼:').strip()for user_dic in user_list: #遍歷列表中所有記錄是否與輸入的名字密碼匹配if username == user_dic['name'] and passwd == user_dic['passwd']:current_dic['username']=username #記錄下登錄的狀態:拿的就是全局變量的引用current_dic['login']=Trueres = func(*args, **kwargs) #驗證成功了才可以直接運行函數return res #wrapper函數直接結束,不必再加break語句了else:print('用戶名或者密碼錯誤') #此else與for連用,不是循環一次后的if連用。列表中用戶名和密碼全for循環完畢了elif auth_type == 'ldap':print('鬼才特么會玩')res = func(*args, **kwargs)return reselse:print('鬼才知道你用的什么認證方式')res = func(*args, **kwargs)return resreturn wrapperreturn auth_func#對auth_func添加參數,加括號相當于直接運行auth函數,因此在這里向無參數形式當中加入return auth_func @auth(auth_type='filedb') # auth函數的返回值:auth_func=auth(auth_type='filedb')-->@auth_func 附加了一個auth_type # --->index=auth_func(index)這個指向的返回值還是wrapper,繼續執行wrapper def index(): #已經輸入正確用戶名及密碼了print('歡迎來到京東主頁')@auth(auth_type='ldap') def home(name): print('歡迎回家%s' %name)@auth(auth_type='sssssss') def shopping_car(name):print('%s的購物車里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃'))print('before-->',current_dic) index() print('after--->',current_dic) home('產品經理') shopping_car('產品經理')

?

九 超時裝飾器

import sys,threading,timeclass KThread(threading.Thread):"""A subclass of threading.Thread, with a kill()method.Come from:Kill a thread in Python:http://mail.python.org/pipermail/python-list/2004-May/260937.html"""def __init__(self, *args, **kwargs):threading.Thread.__init__(self, *args, **kwargs)self.killed = Falsedef start(self):"""Start the thread."""self.__run_backup = self.runself.run = self.__run # Force the Thread to install our trace.threading.Thread.start(self)def __run(self):"""Hacked run function, which installs thetrace."""sys.settrace(self.globaltrace)self.__run_backup()self.run = self.__run_backupdef globaltrace(self, frame, why, arg):if why == 'call':return self.localtraceelse:return Nonedef localtrace(self, frame, why, arg):if self.killed:if why == 'line':raise SystemExit()return self.localtracedef kill(self):self.killed = Trueclass Timeout(Exception):"""function run timeout"""def timeout(seconds):"""超時裝飾器,指定超時時間若被裝飾的方法在指定的時間內未返回,則拋出Timeout異常"""def timeout_decorator(func):"""真正的裝飾器"""def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))def _(*args, **kwargs):result = []new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list'oldfunc': func,'result': result,'oldfunc_args': args,'oldfunc_kwargs': kwargs}thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)thd.start()thd.join(seconds)alive = thd.isAlive()thd.kill() # kill the child threadif alive:raise Timeout(u'function run too long, timeout %d seconds.' % seconds)else:return result[0]_.__name__ = func.__name___.__doc__ = func.__doc__return _return timeout_decorator@timeout(5)def method_timeout(seconds, text):print('start', seconds, text)time.sleep(seconds)print('finish', seconds, text)return secondsmethod_timeout(6,'asdfasdfasdfas')

?

轉載于:https://www.cnblogs.com/Josie-chen/p/8707322.html

總結

以上是生活随笔為你收集整理的函数闭包与装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。