Python的裝飾器用法學習筆記,python學習筆記
在python中常看到在定義函數是使用@func. 這就是裝飾器, 裝飾器是把一個函數作為參數的函數,常常用於擴充已有函數,即不改變當前函數狀態下增加功能.
def run(): print "I'm run."
我有這麼一個函數, 我想知道這個函數什麼時候開始什麼時候結束. 我應該這麼寫
def run(): print time.ctime() print "I'm run." print time.ctime()
但是如果不允許修改函數的話就需要裝飾器了
def count(func): def wrapper(): print time.ctime() ret = func() print time.ctime() return ret return wrapper@countdef run(): print "I'm run." # print '2015-4-10'
eg:
def now(): print '2015-4-10'f = nowf()
函數有一個__name__ 對象 可通過 dir(func) func為定義的函數名
now.__name__ # print 'now'f.__name__ # print 'now'print f # print '<function now at 0x000000000213A908>'print now # print '<function now at 0x000000000213A908>'
我們通過裝飾器列印log日誌
def log(func): def wrapper(*args, **kwargs): print "call %s()" % func.__name__ return func(*args, **kwargs) return wrapper@logdef now(): print '2015-4-10'now() # print 'call now()'
其實裝飾器修飾函數相當於, now = log(now) 也就是裝飾器函數把被修飾的函數當參數後賦給同名的變數
functools.wraps 函數
當我們使用了裝飾器後now的__name__值發生了改變
# 沒有使用前now.__name__ # print 'now'# 使用後now.__name__ # print 'wrapper'
當我們使用裝飾器前,now.__name__使用的是當前now函數,但使用後 now這個函數其實是 log(now) 也就是log函數的傳回值也就是被包裹的wrapper. 解決方案是functools.wraps函數.
裝飾閉包, 使用前得調用 import functools
def log(func): @functools.wraps(func) def wrapper(*args, **kwargs): ...
帶參數的裝飾器
如果decorator需要傳入參數, 那就需要在寫一個返回decorator的高階函數. 寫出來更複雜.
def login(level): def _deco(func): def wrapper(*args, **kwargs): if level >= 5: print '使用者 VIP 等級 %d' % int(level-5) else: print '使用者 屌絲 等級 %d' % abs(level-5) return func(*args, **kwargs) return wrapper return _deco@login(5)def user(username): print 'welcome, %s' % username# 使用者vip 等級0# welcome, minkuser('mink')
帶參數的decorator等於func = 裝飾器函數(裝飾器參數)(func)
裝飾器類
通過類的__call__可以想使用函數一樣使用類
class A(object): def __init__(self, func): self.func = func def __call__(self): return self.func() ** 2@Adef foo(): return 10print foo() # print 100