本篇文章給大家分享的是有關(guān)Python中如何淺談裝飾器,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)新互聯(lián)專注于葫蘆島企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站開發(fā),商城系統(tǒng)網(wǎng)站開發(fā)。葫蘆島網(wǎng)站建設(shè)公司,為葫蘆島等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站開發(fā),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
一 裝飾器是什么
裝飾器是一個(gè)用于封裝函數(shù)或者類的代碼工具,顯式地將封裝器作用于函數(shù)或者類上,達(dá)到程序運(yùn)行時(shí)動(dòng)態(tài)增加功能的目的。對于函數(shù)運(yùn)行前處理常見前置條件(常見的web登陸授權(quán)驗(yàn)證),或者在函數(shù)執(zhí)行之后做善后工作(比如異常處理,記錄log 等等)。
二 如何使用裝飾器
裝飾器本質(zhì)上就是一個(gè)可用接受調(diào)用也可以返回調(diào)用的高階函數(shù)。該函數(shù)以被裝飾的函數(shù)為參數(shù)(還可以加上其他值作為參數(shù))。在裝飾器內(nèi)進(jìn)行裝飾器的邏輯處理,執(zhí)行被裝飾函數(shù),并返回一個(gè)裝飾過的函數(shù),聽起來是不是有點(diǎn)繞,Talk is cheap,show me the code .
下面使用函數(shù)now 和函數(shù)add作為例子,
import datetime
def now():
print 'now is ', datetime.datetime.today()
def add(x, y):
ret = x + y
print '{x} + {y} = {retval}'.format(x=x,y=y,retval=ret)
2.1 裝飾器語法
有兩種方式顯示調(diào)用裝飾器的方法。
方法一:func = deco(func)
方法二:Python 2.5之后 為裝飾器引入了特殊的語法 @ --語法糖,在裝飾器名稱前使用@ 符號(hào),添加在被裝飾的函數(shù)定義之前。
@deco
def now():
print 'now is ', datetime.datetime.today()
# 調(diào)用now
now()
小編將從 參數(shù)這個(gè)角度來由淺入深介紹裝飾器,函數(shù)有不帶參數(shù)和帶參數(shù)的兩種情況,裝飾器也有帶參數(shù)和不帶參數(shù)的兩種情況,裝飾器對處理帶參數(shù)和不帶參數(shù)的情況也會(huì)有鎖不同。
2.2 不帶參數(shù)的情況
我們需要在調(diào)用函數(shù) now 之前和之后加上調(diào)用記錄。
def deco(func):
print 'begin call %s():' % (func.__name__)
func()
print 'end call %s():' % (func.__name__)
return func #裝飾器的參數(shù)是被裝飾的函數(shù)對象,返回原函數(shù)的對象。
yangyiDBA:test yangyi$ python 1.py
begin call now():
now is 2017-05-01 14:40:57.309836
end call now():
now is 2017-05-01 14:40:57.309868
但是從上面的例子看 結(jié)果輸出了兩次now 時(shí)間,明顯不符合我們的要求,因?yàn)檠b飾器必須返回被調(diào)用函數(shù),return func的時(shí)候發(fā)生了第二次。后面我們會(huì)解決這個(gè)問題。
2.3 帶參數(shù)的情況,因?yàn)楹瘮?shù)的參數(shù)個(gè)數(shù)是不確定的 ,我們需要借助(*args, **kwargs),自動(dòng)適應(yīng)變參和命名參數(shù)。
#!/usr/bin/env python
# coding:utf-8
import datetime
import functools
def deco(func):
@functools.wraps(func) #
def wrapper(*args, **kw):
print 'begin call %s():' % (func.__name__)
result=func(*args, **kw) # 如果函數(shù)無返回值 ,可以直接使用func(*args, **kw)
print 'end call %s():' % (func.__name__)
return result #這里 result 是為了func 有返回值,
return wrapper
@deco
def add(x, y):
ret = x + y
print '{x} + {y} = {retval}'.format(x=x,y=y,retval=ret)
@deco
def now():
print 'now is ', datetime.datetime.today()
add(2,5)
now()
上面的裝飾器做了如下事情
1 函數(shù)func作為參數(shù)傳給 deco()。
2 functool.wraps 將func 的屬性復(fù)制給 warper。
3 執(zhí)行函數(shù)func前后執(zhí)行某些動(dòng)作。
4 返回結(jié)果。
5 返回wrapper 函數(shù)對象。
這里特別說明functool.wraps的作用,由于裝飾器導(dǎo)致解釋器認(rèn)為函數(shù)本身發(fā)生了改變,在某些情況下可能會(huì)導(dǎo)致一些問題。Python通過functool.wraps解決了這個(gè)問題:
在編寫裝飾器時(shí),在實(shí)現(xiàn)前加入 @functools.wraps(func) 可以保證裝飾器不會(huì)對被裝飾函數(shù)造成影響。
特別說明其他要使用裝飾器的時(shí)候會(huì)有其他的寫法 比如直接返回被裝飾的函數(shù)。
def deco(func):
@functools.wraps(func) #
def wrapper(*args, **kw):
print 'begin call %s():' % (func.__name__)
return func(*args, **kw)
return wrapper
輸出
yangyiDBA:test yangyi$ python 1.py
begin call add():
2 + 5 = 7
end call add():
begin call now():
now is 2017-05-01 15:20:51.597859
end call now():
2.4 帶參數(shù)的裝飾器
如果裝飾器本身傳入?yún)?shù),就需要編寫一個(gè)返回decorator的高階函數(shù),寫出來會(huì)更復(fù)雜。比如,要自定義log的文本:
#!/usr/bin/env python
# coding:utf-8
import datetime
import functools
def deco(text):
def _deco(func):
def wrapper(*args, **kw):
print '%s, begin call %s():' % (text,func.__name__)
result=func(*args, **kw) # 如果函數(shù)無返回值 ,可以直接使用func(*args, **kw)
print '%s, end call %s():' % (text,func.__name__)
return result #這里 result 是為了func 有返回值,
return wrapper
return _deco
@deco("yangyi")
def add(x, y):
ret = x + y
print '{x} + {y} = {retval}'.format(x=x,y=y,retval=ret)
@deco("youzan")
def now():
print 'now is ', datetime.datetime.today()
add(2,5)
now()
測試結(jié)果:
yangyiDBA:test yangyi$ python 2.py
yangyi, begin call add():
2 + 5 = 7
yangyi, end call add():
youzan, begin call now():
now is 2017-05-01 18:47:54.728296
youzan, end call now():
2.5 Python內(nèi)置裝飾器
在Python中有三個(gè)內(nèi)置的裝飾器,都是跟class相關(guān)的:staticmethod、classmethod 和property。
staticmethod 是類靜態(tài)方法,其跟成員方法的區(qū)別是沒有 self 參數(shù),并且可以在類不進(jìn)行實(shí)例化的情況下調(diào)用
classmethod 與成員方法的區(qū)別在于所接收的第一個(gè)參數(shù)不是 self (類實(shí)例的指針),而是cls(當(dāng)前類的具體類型)
property 是屬性的意思,表示可以通過通過類實(shí)例直接訪問的信息
2.6 跨文件調(diào)用,因?yàn)檠b飾器本質(zhì)是一個(gè)函數(shù)。在工程實(shí)現(xiàn)里我們可以通過創(chuàng)建一個(gè)公用的decorator,作為基礎(chǔ)裝飾器供其他函數(shù)調(diào)用。
Python一切皆對象,函數(shù)也是,也可以賦值給其他變量,理解這點(diǎn)再去理解裝飾器就容易多了。
以上就是Python中如何淺談裝飾器,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。