python中decorator的用法及原理(一)
0、 概念
什麼叫裝飾器,其實也可以叫做包裝器。即對於一個既有的函式func(args),在呼叫它之前和之後,我們希望都做一些事情,把這個函式包裝起來。
python中的裝飾器分為兩類:函式裝飾器和類裝飾器。
這裡我們先討論函式裝飾器。
1. 不帶引數的decorator
(1) 基本用法:
def decorator1(func): def dec(*args): print 'pre action' result = func(*args) print 'post action' return result return dec @decorator1 def test_f1(name): print name return None test_f1('name1') #out: preaction/name1/post action test_f1('name2') #out: preaction/name2/post action
(2) 這種現象的內部原理:
在python內部,當你做了這件事情:
@decorator1
def test_f1(name):
其實就是 test_f1 = decorator1(test_f1) #即test_f1作為引數傳遞給func。
此後的test_f1是裝飾器中的dec函式物件了,而不是原來的函式的名稱。當呼叫test_f1(‘name1’)的時候,其實呼叫的是dec(‘name1’)函式,而在dec函式內部,又呼叫了func,這樣就造成了裝飾器的效果。
這也解釋了func是被裝飾函式,*arg是被裝飾函式的引數—這種現象了。
2. 帶引數的decorator
(1) 基本用法:
def wap(name): def decorator1(func): def dec(*args): print name print 'pre action' result = func(*args) print 'post action' return result return dec return decorator1 @wap('f1') def test_f1(name): print name return None @wap('f2') def test_f2(name): print name return None test_f1('name1') #out: f1/pre action/name1/post action test_f1('name2') #out: f2/pre action/name2/post action
帶引數的decorator,作用是通過傳遞引數可以定製不同的裝飾器。
(2) 內部原理
這裡和上面 不帶引數的decorator類似,
@wap('f1')
def test_f1(name):
內部邏輯為: test_f1 = wap(‘f1’)(test_f1)
這裡wap(‘f1’)返回是decorator1函式物件,這樣的話,wap(‘f1’)(test_f1)其實就是decorator1(test_f1),這樣就和上面的一樣了。只不過這裡傳遞了一個引數’f1’進入decorator內部,使得我們可以操作這個引數。
3. 函式decorator也可以修飾類成員函式
class FOO:
@decorator1
def fun(self):
print self.name
注意此時fun的self會被傳遞到decorator1中。此時把self看做普通的函式入參。
4. 函式decorator的疊加
(1) 用法
def decorator1(func):
def dec(*args):
print 'd1 pre'
result = func(*args)
print 'd1 post'
return result
return dec
def decorator2(func):
def dec(*args):
print 'd2 pre'
result = func(*args)
print 'd2 post'
return result
return dec
@decorator1
@decorator2
def test(name):
print name
test('test') #out: d1 pre/d2 pre/test/d1 post/d2 post
(2) 原理
@decorator1
@decorator2
def test(name):
print name
和上面的類似,內部原理是:
test = decorator1(decorator2(test))
注意decorator1(decorator2(test)),不是說先執行decorator2(test),再執行decorator1。
而是先把decorator2(test)作為引數,最先執行decorator1,然後再執行decorator2.。
參考文章:http://thecodeship.com/patterns/guide-to-python-function-decorators/