【Python】淺談裝飾器
一 裝飾器是什麼
裝飾器是一個用於封裝函式或者類的程式碼工具,顯式地將封裝器作用於函式或者類上,達到程式執行時動態增加功能的目的。對於函式執行前處理常見前置條件(常見的web登陸授權驗證),或者在函式執行之後做善後工作(比如異常處理,記錄log 等等)。
二 如何使用裝飾器
裝飾器本質上就是一個可用接受呼叫也可以返回撥用的高階函式。該函式以被裝飾的函式為引數(還可以加上其他值作為引數)。在裝飾器內進行裝飾器的邏輯處理,執行被裝飾函式,並返回一個裝飾過的函式,聽起來是不是有點繞,Talk is cheap,show me the code .
本文使用函式now 和函式add作為例子,
2.1 裝飾器語法
有兩種方式顯示呼叫裝飾器的方法。
方法一:func = deco(func)
方法二:Python 2.5之後 為裝飾器引入了特殊的語法 @ --語法糖,在裝飾器名稱前使用@ 符號,新增在被裝飾的函式定義之前。
本文將從 引數這個角度來由淺入深介紹裝飾器,函式有不帶引數和帶引數的兩種情況,裝飾器也有帶引數和不帶引數的兩種情況,裝飾器對處理帶引數和不帶引數的情況也會有鎖不同。
2.2 不帶引數的情況
我們需要在呼叫函式 now 之前和之後加上呼叫記錄。
但是從上面的例子看 結果輸出了兩次now 時間,明顯不符合我們的要求,因為裝飾器必須返回被呼叫函式,return func的時候發生了第二次。後面我們會解決這個問題。
2.3 帶引數的情況,因為函式的引數個數是不確定的 ,我們需要藉助(*args, **kwargs),自動適應變參和命名引數。
上面的裝飾器做了如下事情
1 函式func作為引數傳給 deco()。
2 functool.wraps 將func 的屬性複製給 warper。
3 執行函式func前後執行某些動作。
4 返回結果。
5 返回wrapper 函式物件。
這裡特別說明functool.wraps的作用,由於裝飾器導致直譯器認為函式本身發生了改變,在某些情況下可能會導致一些問題。Python透過functool.wraps解決了這個問題:
在編寫裝飾器時,在實現前加入 @functools.wraps(func) 可以保證裝飾器不會對被裝飾函式造成影響。
特別說明其他要使用裝飾器的時候會有其他的寫法 比如直接返回被裝飾的函式。
輸出
2.4 帶引數的裝飾器
如果裝飾器本身傳入引數,就需要編寫一個返回decorator的高階函式,寫出來會更復雜。比如,要自定義log的文字:
測試結果:
2.5 Python內建裝飾器
在Python中有三個內建的裝飾器,都是跟class相關的:staticmethod、classmethod 和property。
staticmethod 是類靜態方法,其跟成員方法的區別是沒有 self 引數,並且可以在類不進行例項化的情況下呼叫
classmethod 與成員方法的區別在於所接收的第一個引數不是 self (類例項的指標),而是cls(當前類的具體型別)
property 是屬性的意思,表示可以透過透過類例項直接訪問的資訊
2.6 跨檔案呼叫,因為裝飾器本質是一個函式。在工程實現裡我們可以透過建立一個公用的decorator,作為基礎裝飾器供其他函式呼叫。
三 小結
Python一切皆物件,函式也是,也可以賦值給其他變數,理解這點再去理解裝飾器就容易多了。剛剛研究裝飾器,總結的可能比較淺顯,想要深入學習裝飾器的可以看看下面的 參考文章。
四 參考文章
1 《Python高階程式設計》 第一章裝飾器
2 《》
3 Python裝飾器學習(九步入門)
4 《詳解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)
有兩種方式顯示呼叫裝飾器的方法。
方法一: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
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():
如果裝飾器本身傳入引數,就需要編寫一個返回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():
在Python中有三個內建的裝飾器,都是跟class相關的:staticmethod、classmethod 和property。
staticmethod 是類靜態方法,其跟成員方法的區別是沒有 self 引數,並且可以在類不進行例項化的情況下呼叫
classmethod 與成員方法的區別在於所接收的第一個引數不是 self (類例項的指標),而是cls(當前類的具體型別)
property 是屬性的意思,表示可以透過透過類例項直接訪問的資訊
2.6 跨檔案呼叫,因為裝飾器本質是一個函式。在工程實現裡我們可以透過建立一個公用的decorator,作為基礎裝飾器供其他函式呼叫。
三 小結
Python一切皆物件,函式也是,也可以賦值給其他變數,理解這點再去理解裝飾器就容易多了。剛剛研究裝飾器,總結的可能比較淺顯,想要深入學習裝飾器的可以看看下面的 參考文章。
四 參考文章
1 《Python高階程式設計》 第一章裝飾器
2 《》
3 Python裝飾器學習(九步入門)
4 《詳解Python的裝飾器》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-2138264/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 淺談Python裝飾器Python
- 淺談TypeScript型別、介面、裝飾器TypeScript型別
- 粗淺聊聊Python裝飾器Python
- 談一談Python中的裝飾器Python
- python裝飾器2:類裝飾器Python
- Python裝飾器探究——裝飾器引數Python
- 淺談ES7的修飾器
- Python 裝飾器Python
- Python裝飾器Python
- 裝飾器 pythonPython
- Python 裝飾器裝飾類中的方法Python
- 通俗易懂的談談裝飾器模式模式
- Python裝飾器模式Python模式
- python的裝飾器Python
- 1.5.3 Python裝飾器Python
- Python 裝飾器(一)Python
- Python 裝飾器原理Python
- 草根學Python(十六) 裝飾器(逐步演化成裝飾器)Python
- python 之裝飾器(decorator)Python
- Python深入05 裝飾器Python
- Python裝飾器詳解Python
- Python中的裝飾器Python
- 初識Python裝飾器Python
- Python 裝飾器的理解Python
- python裝飾器介紹Python
- Python3 裝飾器解析Python
- Python 語法之裝飾器Python
- Python裝飾器高階用法Python
- python裝飾器入門探究Python
- python 裝飾器 part2Python
- python裝飾器有哪些作用Python
- python裝飾器是什麼Python
- Python 裝飾器簡單示例Python
- python中裝飾器的原理Python
- Python閉包與裝飾器Python
- Python之函式裝飾器Python函式
- Python深入分享之裝飾器Python
- Python裝飾器的前世今生Python