大家都知道裝飾器是乙個很著名的設計模式,經常被用於aop(面向切面程式設計)的場景,較為經典的有插入日誌,效能測試,事務處理,web許可權校驗,cache等。
python語言本身提供了裝飾器語法(@),典型的裝飾器實現如下:
def function():
pass
@實際上是python2.4才提出的語法糖,針對python2.4以前的版本有另一種等價的實現:
def function():
pass
函式包裝器 – 經典實現
def function():
pass
類包裝器 – 更易於理解
def __call__(self, *args, **kwargs):
def function():
pass
當我們談到乙個函式時,通常希望這個函式的屬性像其文件上描述的那樣,是被明確定義的,例如__name__
和__doc__
。
針對某個函式應用裝飾器時,這個函式的屬性就會發生變化,但這並不是我們所期望的。
def function():
pass
>>> print(function.__name__)
python標準庫提供了functools.wraps()
,來解決這個問題。
import functools
def function():
pass
>>> print(function.__name__)
function
然而,當我們想要獲取被包裝函式的引數(argument
)或源**(source code
)時,同樣不能得到我們想要的結果。
import inspect
def function(arg1, arg2): pass
>>> print(inspect.getargspec(function))
argspec(args=, varargs='args', keywords='kwargs', defaults=none)
>>> print(inspect.getsource(function))
class class(object):
@classmethod
def cmethod(cls):
pass
traceback (most recent call last):
file "", line 1, in
file "", line 3, in class
attributeerror: 'classmethod' object has no attribute '__module__'
然而,在python3下執行,另乙個問題出現了:
class class(object):
@classmethod
def cmethod(cls):
pass
>>> class.cmethod()
traceback (most recent call last):
file "classmethod.py", line 15, in
class.cmethod()
typeerror: 'classmethod' object is not callable
這是因為包裝器認定被包裝的函式(@classmethod
)是可以直接被呼叫的,但事實並不一定是這樣的。被包裝的函式實際上可能是描述符(descriptor
),意味著為了使其可呼叫,該函式(描述符)必須被正確地繫結到某個例項上。關於描述符的定義,可以參考
儘管大家實現裝飾器所用的方法通常都很簡單,但這並不意味著它們一定是正確的並且始終能正常工作。
如同上面我們所看到的,functools.wraps()
可以幫我們解決__name__
和__doc__
的問題,但對於獲取函式的引數(argument
)或源**(source code
)則束手無策。
以上問題,wrapt都可以幫忙解決,詳細用法可參考其官方文件:
Python 裝飾器使用過程中的誤區解讀
大家都知道裝飾器是乙個很著名的設計模式,經常被用於aop 面向切面程式設計 的場景,較為經典的有插入日誌,效能測試,事務處理,web許可權校驗,cache等。python語言本身提供了裝飾器語法 典型的裝飾器實現如下 deffunction pass 實際上是python2.4才提出的語法糖,針對p...
python使用過程中問題
1.檢視python支援的 whl格式 在cmd輸入python 或者 python3.6 import pip print pip.pep425tags.get supported 2.在修改python.exe為python36.exe 任何重新命名 後,pip會報錯 fatal error i...
element ui dialog使用過程中的坑
場景一 我們將dialog寫成乙個可復用的公共元件用於顯示不同內容 如 操作中的修改或新增的彈窗 之後發現dialog的遮罩將彈出層 點選修改或新增後理應由乙個彈窗顯示出來 都蓋住了,而我想要的效果是遮罩只遮住舊的視窗,而當前視窗應該完全顯示 注 是使用easyui的panel和window來包裹的...