python的裝飾器一直是Python里不太好理解的一部分,但是使用確是非常頻繁的一個東西。用好裝飾器可以讓代碼更加簡潔,更具可讀性,所以這里分享一下我對python裝飾器的理解。
python裝飾器個功效有點類似于java的web開發(fā)中spring面向切面編程的前置后置增強,可以在我們的目標操作前先執(zhí)行一些預處理。經(jīng)常用在輸出日志,性能測試或者事物處理的地方。
如何編寫一個裝飾器
現(xiàn)在來做一個日志增強的功能:
def log(func):
def wrapper(*args, **kwargs):
print 'call %s()' % func.__name__
return func(*args, **kwargs)
return wrapper
@log
def hello():
print 'hello'
if __name__ == '__main__':
hello()
output:
call hello()
hello
這里新建了一個函數(shù)叫l(wèi)og接收一個函數(shù)做為參數(shù)內(nèi)部有一個函數(shù)叫做wrapper的功能就是打印一句日志。當我們調(diào)用hello()的時候不僅hello本身會執(zhí)行還會執(zhí)行l(wèi)og里面的打印語句。其實我們在def hello
前面加上的@log
的作用相當于hello = log(hello)
而@符號只是python給它的一個語法糖而已,看起來更簡潔美觀。
functools @wraps
由于我們的裝飾器其實相當于調(diào)用hello=log(hello)
而log是返回wrapper函數(shù)的,所以如果這時候我們打印hello.__name__
會發(fā)現(xiàn)輸出是wrapper
這樣我們的函數(shù)名字都變了。如果你對函數(shù)名又要求或者用到函數(shù)的一些屬性,這樣就會造成一些不可預測的后果。于是python在2.5版本之后的functools
模塊中加入了一個裝飾器叫做@wraps
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print 'call %s()' % func.__name__
return func(*args, **kwargs)
return wrapper
@log
def hello():
print 'hello'
if __name__ == '__main__':
print hello.__name__
這里我們在wrapper
上面加入了一個這個裝飾器再打印hello的名字的適合就不是wrapper
而是hello
了,其實@functools.wraps(func)
就是把wrapper函數(shù)的各個屬性更新為我們想要裝飾的函數(shù)的屬性。
為裝飾器添加參數(shù)
經(jīng)常我們在一些web框架里可以看到很多裝飾器用來路由web頁面的url同時也加入了很多參數(shù)。比如flask里面:
@app.route('/logout')
def logout():
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
這里使用了@app.route這個裝飾器并且傳入了一個參數(shù),那么怎么編寫一個可以傳入?yún)?shù)的裝飾器呢?
下面我們寫一個可以接收一個參數(shù)的裝飾器:
def assign_info(text):
def decorater(func):
@functools.wraps(func)
def wrapper():
print 'info:' + text
return func()
return wrapper
return decorater
@ assign_info('decorater input')
def hello():
print 'hello---'
if __name__ == '__main__':
hello()
可以看到我們這個裝飾器變成了三層第一次是可以接收我們的參數(shù)的函數(shù),里面是裝飾器函數(shù),最里面是wrapper函數(shù),然后再一層一層的返回。剛剛說到我們寫的那個log裝飾器相當于調(diào)用hello=log(hello)
,那現(xiàn)在我們的三層的又是怎么調(diào)用的呢?其實這相當于hello=assign_info('decorater input')(hello)
總結(jié):python的裝飾器在很多地方都經(jīng)常用到,所以理解并掌握它非常必要,學會了裝飾器可以讓代碼變得更簡潔,開發(fā)效率也可以得到顯著提高,在很多比如權(quán)限管理,日志管理等地方我們都可以做成裝飾器來處理。