Python學習筆記(12) 裝飾器詳解

2021-07-26 04:34:35 字數 4645 閱讀 1868

之前在筆記(11)中,簡單寫了裝飾器的用法,看了廖老師的教程感覺頭大了不少,老糾結return到底要不要,又網上蒐集許多講解,現分步驟詳細描述下乙個常規的裝飾器的寫法。不足之處今後再補充。(日誌的列印格式我是手動改的,為了看著舒服額已→_→)

**:(就是簡單的輸出字串)

def

myfun

(): print('├2017-01-16┤')

myfun()

結果:

├2017-01-16┤
**:(簡單的使用裝飾器)

def

log(fun):

print('┌--before--┐')

fun() # 此處呼叫傳進來的函式

print('└--after---┘')

defmyfun

(): print('├2017-01-16┤')

myfun = log(myfun) # 將函式傳遞給log函式,再用變數myfun指向它

print(myfun) # 此時的myfun沒指向任何記憶體位址,因為log函式沒有返回值

結果:

┌--before--┐

├2017-01-16┤

└--after---┘

none

**:(使用@語法,吧decorator放在函式的定義的地方)

def

log(fun):

print('┌--before--┐')

fun()

print('└--after---┘')

@log # 只在此處新增了@log 此句相當於 myfun = log(myfun)

defmyfun

(): print('├2017-01-16┤')

# myfun = log(myfun)

print(myfun) # 仍舊沒有指向記憶體位址

結果:

┌--before--┐

├2017-01-16┤

└--after---┘

none

**:(log內定義包裝函式,並將此函式返回)

def

log(fun):

defcover

():# 定義包裝函式

print('┌--before--┐')

fun()

print('└--after---┘')

return cover # 將包裝函式返回,注意返回的是函式名(即變數),不是呼叫函式cover()

@log # 此時 myfun = log(myfun) 中,myfun指向了cover,但是並沒有呼叫,和第3步直接呼叫不同

defmyfun

(): print('├2017-01-16┤')

print(myfun) # myfun已經指向了cover

myfun()

myfun() # 可呼叫多次

結果:log處並沒有呼叫,所以一共輸出2次

.cover at 0x0000000000bcdd08>

┌--before--┐

├2017-01-16┤

└--after---┘

┌--before--┐

├2017-01-16┤

└--after---┘

**:(只是將包裝函式增加引數)

def

log(fun):

defcover

(a, b):

# 此處的引數需要和原函式引數相同

print('┌--before--┐')

result = fun(a, b) # 呼叫函式後,將結果賦值給result變數

print('└--after---┘')

return result # 此時可返回結果

return cover

@log

defmyfun

(a, b):

print('├2017-01-16┤')

return a * b

print(myfun)

print(myfun(3, 6)) # 函式結果已經返回

print(myfun(6, 9))

結果:

.cover at 0x000000000073dd08>

┌--before--┐

├2017-01-16┤

└--after---┘

18┌--before--┐

├2017-01-16┤

└--after---┘

54

因為自定義的函式引數型別和個數不確定,所以根據之前函式引數的筆記(7),可以將任意函式引數表示成func(*args, **kw),所以上述**cover函式的定義可以改為

def

cover

(*args, **kwargs):

# 此處的引數需要和原函式引數相同

print('┌--before--┐')

result = fun(*args, **kwargs)

print('└--after---┘')

return result

此時不論其他函式多少個引數,都會按照裝飾器的邏輯在函式執行前後加上log語句

**:(比如,自定義log文字內容(裝飾器外控制))

def

log(message):

# log傳入的引數變為14行傳入的引數

defdeco

(fun):

# 引數fun是原函式

defcover

(*args, **kwargs):

print('┌--%s--┐' % message) # 使用傳入的引數message列印日誌

result = fun(*args, **kwargs)

print('└--%s--┘' % message)

return result

return cover

return deco

@log('my message') # 此句相當於 myfun = log('my message')(myfun)

defmyfun

(a, b):

print('├--2017-01-16--┤')

return a * b

print(myfun)

print(myfun(3, 6))

print(myfun(6, 9))

結果:

.deco..cover at 0x00000000011cdd90>

┌--my message--┐

├--2017-01-16--┤

└--my message--┘

18┌--my message--┐

├--2017-01-16--┤

└--my message--┘

54

e.g. 同時相容loglog('sth')

**:

def

log(message):

# log傳入的引數變為14行傳入的引數

defdeco

(fun, msg=message):

# 引數fun是原函式

defcover

(*args, **kwargs):

print('┌--%s--┐' % msg) # 使用傳入的引數列印日誌

result = fun(*args, **kwargs)

print('└--%s--┘' % msg)

return result

return cover

if isinstance(message, str): # 是字串的情況下,正常執行

return deco

else:

return deco(message, '---') # 不是字串或者為空等的情況,此時的message是傳過來的函式,呼叫deco(),返回變數指向cover函式

@log('my message') # 此句相當於 myfun = log('my message')(myfun)

defmyfun

(a, b):

print('├--2017-01-16--┤')

return a * b

@log

defmyfun2

(): print('├-other-┤')

myfun(1, 2)

myfun2()

結果:

┌--my message--┐

├--2017-01-16--┤

└--my message--┘

┌-------┐

├-other-┤

└-------┘

python 學習筆記 day12 裝飾器高階

裝飾器的原則 開放封閉原則 對擴充套件是開放的,對修改是封閉的 裝飾器的作用 在不改變原函式呼叫的情況下,擴充套件被裝飾函式的功能 可以在裝飾器函式內部,在被裝飾函式的前後分別新增相應的功能 裝飾器函式的本質 裝飾器函式本質上就是乙個閉包函式 裝飾器函式固定模式 裝飾器函式 def inner ar...

Python 學習筆記 裝飾器

裝飾器也是乙個函式 巢狀 用來裝飾某個函式,來看下面的 import time deftime count func def start time.time func end time.time print this funnction costs end start deftellhi print...

Python學習筆記 裝飾器

裝飾器 概念 是乙個閉包,把乙個函式當做引數返回乙個替代版的函式,本質上就是乙個返回函式的函式 簡單的裝飾器 def func1 print welcome to beijing def outer func def inner print func return inner f是函式func1的加...