不知不覺已經連續寫了13天了,很享受每天寫公衆号這個過程,通過寫作将自己每天學習的Python知識分享出來,但是學習的東西是零散的,需要自己通過一定的邏輯順序将零散的知識串起來,這很鍛煉自己的邏輯能力和寫作能力。
其實我也很讨厭很多知識混雜在一起,讓人摸不着頭緒,但是每當自己整理好一個知識點後,就覺得非常清爽,理清了頭緒、鞏固了知識。
今天一起學習一下Python裡面裝飾器這個概念吧!
需要實作記錄多個函數運作的時間這個功能,那最直接的做法如下所示
import time
def f1():
print(time.time())
print('This is a function')
def f2():
print(time.time())
print('This is a function')
f1()
f2()
複制
1557198935.042486
This is a function
1557198935.042486
This is a function
複制
但是,這樣做是違背Python的原則——對修改是封閉的,對擴充是開放的。
于是可以稍加修改,為了列印兩個函數的運作時間,又單獨編寫了一個專門列印時間的函數,将函數作為一個變量傳入到這個列印時間的函數中,然後在下面進行調用。
import time
def f1():
print('This is a function')
def f2():
print('This is a function')
def print_current_time(func):
print(time.time())
func()
print_current_time(f1)
print_current_time(f2)
複制
但是這段代碼也不好,表面看着由一個列印時間的函數負責,其實列印時間的這個函數和其他的兩個函數相關聯性很不好,它的實質和下面這段代碼是沒差別的。
import time
def f1():
print(time.time())
def f2():
print(time.time())
print('This is a function')
f1()
print('This is a function')
f2()
複制
為了解決這個問題,我們就需要用到今天的主角——裝飾器。
重新定義一個裝飾器函數,再嵌套一個wrapper函數,這個函數主要負責封裝。具體代碼如下:
import time
def decorator(func): #裝飾器
def wrapper(): #被封裝
print(time.time())
func()
return wrapper
def f1():
print('This is a function')
f = decorator(f1)
f()
複制
大家可以看到雖然定義了裝飾器這個函數,但是調用的時候依然很麻煩,和上面定義一個列印時間的函數沒什麼差別,看不出來有什麼優勢?
為了進一步說明裝飾器的優勢,這裡需要引入文法糖這個概念。直接在函數f1的前面加入文法糖,就可以實作列印時間的功能。
import time
def decorator(func): #裝飾器
def wrapper(): #被封裝
print(time.time())
func()
return wrapper
@decorator
def f1():
print('This is a function')
f1()
複制
大家可以看到這裡,通過直接調用f1()就可以實作功能。
現在考慮給2個函數列印運作時間,而且給兩個函數傳入不同個數的參數,比如說,f1(func_name)、f2(func_name1,func_name2),那該怎麼實作這個功能呢?
在這裡裝飾器隻有一個,我們怎麼将它變成一個通用的,展現出裝飾器的複用性?這裡需要用到可變參數args這個概念,它表示一組參數,具體操作如下:
import time
def decorator(func): #裝飾器
def wrapper(*args): #被封裝 可變參數args表示一組參數
print(time.time())
func(*args)
return wrapper
@decorator
def f1(func_name):
print('This is a function'+func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
f1('test func')
f2('test func1','test func2')
複制
如果再将難度提升一下,在前兩個函數的基礎,增加第三個函數,且第三個函數傳入三個參數,那又該怎麼操作呢?
這裡需要用到**kw這個形參,它表示一個字典,将它傳入到wrapper函數中,具體代碼如下
import time
def decorator(func): #裝飾器
def wrapper(*args,**kw): #被封裝
print(time.time())
func(*args,**kw)
return wrapper
@decorator
def f1(func_name):
print('This is a function'+func_name)
@decorator
def f2(func_name1,func_name2):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
@decorator
def f3(func_name1,func_name2,**kw):
print('This is a function' + func_name1)
print('This is a function' + func_name2)
print(kw)
f1('test func')
f2('test func1','test func2')
f3('test func1','test func2',a=1,b=2,c='1,2,3')
複制
關于裝飾器就學到這,對于一個初學者來說,了解這些基本的裝飾器已經夠了,平時在自己編碼的過程中,可以根據業務需求,有意識的用到裝飾器,這樣會讓你的代碼更加fanastic。