python中的裝飾器
阿新 • • 發佈:2020-08-11
python語言中的裝飾器應該算是這門語言中的一個難點了,作為一個初學者,好像也知道是怎麼回事,可是否真正理解了,那還得存疑。最近偶然看到老男孩的Egon老師的視訊,我才覺得真正明白裝飾器是怎麼一回事了。Egon老師那種抽絲剝繭式的講解,真是讓人耳目一新。雖然有些時候略顯繁瑣,但對於一個困難知識點來說,再沒有這種方式更好的講解了。接下來,我就著剛看過視訊的熱乎近,把我對裝飾器的理解記錄下來,以防止哪一天忘記了。
- 什麼是裝飾器
- 裝飾器一種特殊物件,可以給其它物件新增功能,而不改變所裝飾物件的使用方式。比如說:如果一個函式被一個裝飾器裝飾,那麼從使用者的角度來看,應該感覺不到有任何變化,函式的呼叫方式,引數以及返回值都不發生任何變化。
- 裝飾器用到了一個Python中的一個重要概念:閉包。什麼是閉包?條件有兩個:一是一定要有一個內部函式。二是這個內部函式一定要訪問包含這個內部函式的外層函式的變數。
- 還利用了Python中的函式的特性:可以作為引數傳遞,也可以作為返回值被返回。 - 如何來寫一個裝飾器(以函式裝飾器為例)
- 我們先來考慮,如何給一個函式增加功能,卻不改變它的呼叫方式。
# sol3 - 1: 通過在內外層函式中使用兩次(*args, **kwargs),可以把外層函式的引數原封不動地傳遞到內層。 # 從而就可以把內層函式的引數寫活,但是變更了呼叫方式,要通過wrapper來呼叫index def wrapper(*args, **kwargs): start = time.time() index(*args, **kwargs) stop = time.time() print(stop - start) wrapper('xiaolee', 'zd') # sol 3 -2: 要想不改變函式的呼叫方式,只能通過在wrapper函式外再包上一層函式。這個方案還不能接收內層函式的返回值。 def timer(func): def wrapper(*args, **kwargs): start = time.time() func(*args, **kwargs) stop = time.time() print(stop - start) return wrapper index = timer(index) index('ggg', 'dddd') # sol3 - 3:通過res變數接收內層函式的返回值,並作為wrapper函式的返回值返回。 def timer(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print(stop - start) return res return wrapper index = timer(index) print(index('zz', 'yy')) # sol 4: 語法糖 def timer(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print(stop - start) return res return wrapper @timer def index(x, y): time.sleep(1) print('heloo %s, your company %s' % (x, y)) index('xxxx', 'ccccc')
- 帶引數的裝飾器
# 帶參裝飾器 # 以加簡單的認證功能為例 def authentication(): user = input('Please input your username: ').strip() password = input('Please input your password: ').strip() if user == 'zylee' and password == 'wlsoft': print('authentication successful!!!') return True else: print('authentication failed!!!') return False def auth(db_style): def deco(func): def wrapper(*args, **kwargs): # auth code if db_style == 'mysql': if authentication(): res = func(*args, **kwargs) return res elif db_style == 'file' and authentication(): if authentication(): res = func(*args, **kwargs) return res else: print("error!!!!") return wrapper return deco @auth('mysql') def index(x, y): print('hello, %s and %s' % (x, y)) index('a', 'b')