函數(shù)裝飾器
-
為什么要用裝飾器?
裝飾器本質(zhì)上是一個(gè)函數(shù),該函數(shù)用來處理其他函數(shù),它可以讓其他函數(shù)在不需要修改代碼的前提下增加額外的功能卷要,裝飾器的返回值也是一個(gè)函數(shù)對(duì)象。它經(jīng)常用于有切面需求的場景独榴,比如:插入日志僧叉、性能測(cè)試、事務(wù)處理棺榔、緩存瓶堕、權(quán)限校驗(yàn)等應(yīng)用場景。裝飾器是解決這類問題的絕佳設(shè)計(jì)症歇,有了裝飾器郎笆,我們就可以抽離出大量與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用.概括的講,裝飾器的作用就是為已經(jīng)存在的對(duì)象添加額外的功能忘晤。
-
先定義兩個(gè)個(gè)函數(shù)
def addUser(): print('添加用戶成功宛蚓!') def registUser(): print('添加用戶成功!')
如果用戶想要知道是哪個(gè)函數(shù)添加了用戶设塔,怎么辦凄吏?(略...)
改進(jìn)方法
def debug(): import inspect caller_name = inspect.stack()[1][3] print("[DEBUG]: enter {}()".format(caller_name)) def addUser(): debug() print('添加用戶成功!') def registUser(): debug() print('添加用戶成功!')
但是如果再想要取消這個(gè)功能痕钢,則需要改變兩個(gè)函數(shù):addUser表谊,registUser
**裝飾器的作用很明顯** def debug(func): def wrapper(): print("[DEBUG]: enter {}()".format(func.__name__)) return func() return wrapper @debug def addUser(): print('添加用戶成功!') return 'ok' @debug def registUser(): print('添加用戶成功盖喷!')
-
裝飾器傳參
參數(shù)先傳給裝飾器,裝飾器傳給函數(shù)
def debug(func): def wrapper(name): print("[DEBUG]: enter {}()".format(func.__name__)) func(name) return wrapper @debug def addUser(name): print('添加用戶{0}成功难咕!'.format(name)) @debug def registUser(name): print('添加用戶{0}成功课梳!'.format(name)) addUser('tom') registUser('jack')
如果函數(shù)是有返回值的,則加上return 語句即可
def debug(func): def wrapper(name): print("[DEBUG]: enter {}()".format(func.__name__)) return func(name) #此處加上return return wrapper
-
傳遞可變參數(shù)
def debug(func): def wrapper(*args,**other): print("[DEBUG]: enter {}()".format(func.__name__)) print(other) # 可以在此處對(duì) args和other數(shù)據(jù)進(jìn)行處理 return func(args) return wrapper @debug def addUser(user): print('添加用戶{0}成功余佃!'.format(user)) return user @debug def registUser(user): print('添加用戶{0}成功暮刃!'.format(user)) return user n1=addUser('tom',12,other={'gender': 'M', 'job': 'Engineer'}) n2=registUser('jack')
-
最新版本
最新版本的python導(dǎo)入了functools模塊
from functools import wraps def debug(func): @wraps(func) def wrapper(name): print("[DEBUG]: enter {}()".format(func.__name__)) return func(name) #此處加上return return wrapper @debug def show(s): print(s) show('ppyth')
-
帶參數(shù)的裝飾器
from functools import wraps def debug(*text): def decorated(func): @wraps(func) def wrapper(name): print("[DEBUG]: enter {}()".format(func.__name__)) return func(name) # 此處加上return return wrapper return decorated @debug() #此處的()不可以刪略 def show(s): print(s) show('ppyth')
-
__call__()
所有的函數(shù)都是可調(diào)用對(duì)象。
一個(gè)類實(shí)例也可以變成一個(gè)可調(diào)用對(duì)象爆土,只需要實(shí)現(xiàn)一個(gè)特殊方法call()class Person(object): def __init__(self,name): self.name=name def __call__(self, *args, **kwargs): print('my name is ',self.name) print('my hobby is ',args) p1=Person('tom') p1('reading')
所以椭懊,在Python中,函數(shù)也是對(duì)象步势,對(duì)象和函數(shù)的區(qū)別并不顯著氧猬。
-
類裝飾器(待續(xù).....)
from functools import wraps from datetime import datetime #類的裝飾器寫法,日志 class log(object): def __init__(self, logfile='out.log'): self.logfile = logfile def __call__(self, func): @wraps(func) def wrapped_func(*args, **kwargs): self.writeLog(*args, **kwargs) # 先調(diào)用 寫入日志 return func(*args, **kwargs) # 正式調(diào)用主要處理函數(shù) return wrapped_func #寫入日志 def writeLog(self, *args, **kwargs): time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") log_str = time+' 操作人:{0[0]} 進(jìn)行了【{0[1]}】操作'.format(args) with open(self.logfile, 'a',encoding='utf8') as file: file.write(log_str + '\n') @log() def myfunc(name,age): print('姓名:{0},年齡:{1}'.format(name,age)) if __name__ == '__main__': myfunc('小白', '查詢') myfunc('root', '添加人員') myfunc('小小', '修改數(shù)據(jù)')