本篇文章給大家分享的是有關Python中如何淺談裝飾器,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
一 裝飾器是什么
裝飾器是一個用于封裝函數或者類的代碼工具,顯式地將封裝器作用于函數或者類上,達到程序運行時動態增加功能的目的。對于函數運行前處理常見前置條件(常見的web登陸授權驗證),或者在函數執行之后做善后工作(比如異常處理,記錄log 等等)。
二 如何使用裝飾器
裝飾器本質上就是一個可用接受調用也可以返回調用的高階函數。該函數以被裝飾的函數為參數(還可以加上其他值作為參數)。在裝飾器內進行裝飾器的邏輯處理,執行被裝飾函數,并返回一個裝飾過的函數,聽起來是不是有點繞,Talk is cheap,show me the code .
下面使用函數now 和函數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 裝飾器語法
有兩種方式顯示調用裝飾器的方法。
方法一:func = deco(func)
方法二:Python 2.5之后 為裝飾器引入了特殊的語法 @ --語法糖,在裝飾器名稱前使用@ 符號,添加在被裝飾的函數定義之前。
@deco
def now():
print 'now is ', datetime.datetime.today()
# 調用now
now()
小編將從 參數這個角度來由淺入深介紹裝飾器,函數有不帶參數和帶參數的兩種情況,裝飾器也有帶參數和不帶參數的兩種情況,裝飾器對處理帶參數和不帶參數的情況也會有鎖不同。
2.2 不帶參數的情況
我們需要在調用函數 now 之前和之后加上調用記錄。
def deco(func):
print 'begin call %s():' % (func.__name__)
func()
print 'end call %s():' % (func.__name__)
return func #裝飾器的參數是被裝飾的函數對象,返回原函數的對象。
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
但是從上面的例子看 結果輸出了兩次now 時間,明顯不符合我們的要求,因為裝飾器必須返回被調用函數,return func的時候發生了第二次。后面我們會解決這個問題。
2.3 帶參數的情況,因為函數的參數個數是不確定的 ,我們需要借助(*args, **kwargs),自動適應變參和命名參數。
#!/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) # 如果函數無返回值 ,可以直接使用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 函數func作為參數傳給 deco()。
2 functool.wraps 將func 的屬性復制給 warper。
3 執行函數func前后執行某些動作。
4 返回結果。
5 返回wrapper 函數對象。
這里特別說明functool.wraps的作用,由于裝飾器導致解釋器認為函數本身發生了改變,在某些情況下可能會導致一些問題。Python通過functool.wraps解決了這個問題:
在編寫裝飾器時,在實現前加入 @functools.wraps(func) 可以保證裝飾器不會對被裝飾函數造成影響。
特別說明其他要使用裝飾器的時候會有其他的寫法 比如直接返回被裝飾的函數。
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 帶參數的裝飾器
如果裝飾器本身傳入參數,就需要編寫一個返回decorator的高階函數,寫出來會更復雜。比如,要自定義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) # 如果函數無返回值 ,可以直接使用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()
測試結果:
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內置裝飾器
在Python中有三個內置的裝飾器,都是跟class相關的:staticmethod、classmethod 和property。
staticmethod 是類靜態方法,其跟成員方法的區別是沒有 self 參數,并且可以在類不進行實例化的情況下調用
classmethod 與成員方法的區別在于所接收的第一個參數不是 self (類實例的指針),而是cls(當前類的具體類型)
property 是屬性的意思,表示可以通過通過類實例直接訪問的信息
2.6 跨文件調用,因為裝飾器本質是一個函數。在工程實現里我們可以通過創建一個公用的decorator,作為基礎裝飾器供其他函數調用。
Python一切皆對象,函數也是,也可以賦值給其他變量,理解這點再去理解裝飾器就容易多了。
以上就是Python中如何淺談裝飾器,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。