當不想修改原函數,未函數先後添加功能時,就可使用裝飾器,在函數先後增長功能。緩存
import time def timer(f): def inner(): print("我是裝飾器,我來裝飾了!!!") start = time.time() f() end = time.time() print(start - end) return inner # 返回inner因爲f實現了閉包,直接調用了程序 def func(): time.sleep(1) print("我是小魚,要做做做。。。有本事來裝飾我!") # 經過inner返回,在func先後進行了函數的功能的擴展 t = timer(func) t() # 雖然實現了功能,可是函數的調用名修改了 # 爲了避免改變調用名,能夠賦值給func func = timer(func) func() # 經過裝飾器,實現了不修改函數名的裝飾
在函數前面加,加上@函數名,就能夠實現裝飾器,叫作語法糖閉包
def timer(f): def inner(): print("我是裝飾器,我來裝飾了!!!") start = time.time() f() end = time.time() print(start - end) return inner # 返回inner因爲f實現了閉包,直接調用了程序 @timer def func(): time.sleep(1) print("我是小魚,要做做做。。。有本事來裝飾我!")
import time def timer(f): def inner(a,b): # inner接收傳入的參數 print("我是裝飾器,我來裝飾了!!!") start = time.time() ret = f(a,b) end = time.time() print(start - end) return ("我是裝飾器的返回值!!!",start - end) # 在閉包內部,實現返回值 return inner # 返回inner因爲f實現了閉包,直接調用了程序 @timer def func(a,b): time.sleep(1) print("我是小魚,要做做做。。。有本事來裝飾我!") print("a=%s,b=%s" % (a,b)) ret = func(1,2) # 參數至關於傳遞給inner print(ret)
經過*args和**kwargs傳遞任意參數函數
def warpper(f): def inner(*args, **kwargs): ret = f(*args, **kwargs) return ret return inner @warpper def func(*args, **kwargs): #*和**打散 print("我是被裝飾的函數!") print(args) print(kwargs) func() # 傳空參數 func(1,2,3,4,b=1, a=2) # 傳任意參數 dic1 = {"a":1, "b":2} func(*(1,2,3,4),**dic1) # 打散傳遞
我的觀察結論:*是按順序打散,形參位置:*args中,args打散後爲1 2 3 4,因此args爲(1,2,3,4)this
def outer(*args): print(args) # (1, 2, 3, 4) print(*args) # 1 2 3 4 元祖被打散 def inner(*args): print('innner', args) inner(*args) # 打散傳入inner(1,2,3,4) outer = outer(1,2,3,4)
函數的__doc__和__name__能夠查看函數的說明和名字。url
裝飾器後,函數名和名字都變爲裝飾器的內部函數spa
def warpeer(f): def inner(*args, **kwargs): ''' this is warpper inner :param args: :param kwargs: :return: ''' print("this is innser") ret = f(*args, ** kwargs); return ret return inner @warpeer def func(): print("this is func") print(func.__name__) print(func.__doc__)
加上wraps後,能夠識別到函數本身的doc和namecode
from functools import wraps def warpeer(f): @wraps(f) def inner(*args, **kwargs): ''' this is warpper inner :param args: :param kwargs: :return: ''' print("this is innser") ret = f(*args, ** kwargs); return ret return inner @warpeer def func(): ''' this is func doc :return: ''' print("this is func") print(func.__name__) print(func.__doc__)
# 1.編寫裝飾器,爲多個函數加上認證的功能(用戶的帳號密碼來源於文件), # 要求登陸成功一次,後續的函數都無需再輸入用戶名和密碼 uname = "小魚" upwd = "qwe" LOGTYPE = False def login(func): def in_login(): global LOGTYPE # print(LOGTYPE) if LOGTYPE: # print(LOGTYPE) func() return username = input("請輸入用戶名:") userword = input("請輸入密碼:") if username.strip() == uname and userword.strip() == upwd: ret = func() LOGTYPE = True return ret else: print("用戶名或者密碼錯誤!") pass return in_login @login def shoplist_add(): print("增長一件商品!") @login def shoplist_del(): print("刪除一件商品!") shoplist_add() shoplist_del()
# 1.編寫下載網頁內容的函數,要求功能是:用戶傳入一個url,函數返回下載頁面的結果 # 2.爲題目1編寫裝飾器,實現緩存網頁內容的功能: # 具體:實現下載的頁面存放於文件中,若是文件內有值(文件大小不爲0),就優先從文件中讀取網頁內容,不然,就去下載,而後存到文件中 import os from urllib.request import urlopen as uop def catche(fun): def in_c(*args, **kwargs): file = "catche.txt" if not os.path.exists(file): with open(file, 'wb') as f: f.write("") if os.path.getsize(file) : with open(file, 'rb') as f: return f.read() else: ret = fun(*args, **kwargs) with open(file, 'wb') as f: f.write(b'****catche***' + ret) return ret return in_c @catche def get_url(url): ret = uop(url).read() return ret print(get_url("http://www.baidu.com")) print(get_url("http://www.baidu.com"))