Python 裝飾器使用過程中的誤區解讀

2021-09-02 11:31:53 字數 3331 閱讀 8237

大家都知道裝飾器是乙個很著名的設計模式,經常被用於aop(面向切面程式設計)的場景,較為經典的有插入日誌,效能測試,事務處理,web許可權校驗, cache等。

python語言本身提供了裝飾器語法(@),典型的裝飾器實現如下:

deffunction

():pass

@實際上是python2.4才提出的語法糖,針對python2.4以前的版本有另一種等價的實現:

deffunction

():pass

function=(

function

)函式包裝器 - 經典實現

def(

):def

(*args,**

kwargs

):return

(*args,**

kwargs

)return

deffunction

():pass

類包裝器 - 易於理解

class

(object

):def

__init__

(self,):

self.=

def__call__

(self,*

args,**

kwargs

):return

self.(*

args,**

kwargs

)def

function

():pass

當我們談到乙個函式時,通常希望這個函式的屬性像其文件上描述的那樣,是被明確定義的,例如__name__ 和__doc__ 。

針對某個函式應用裝飾器時,這個函式的屬性就會發生變化,但這並不是我們所期望的。

def(

):def

(*args,**

kwargs

):return

(*args,**

kwargs

)return

deffunction

():pass

>>>

print

(function

.__name__

)python標準庫提供了functools.wraps() ,來解決這個問題。

import

functools

def(

):@functools

.wraps()

def(*

args,**

kwargs

):return

(*args,**

kwargs

)return

deffunction

():pass

>>>

print

(function

.__name__

)function

然而,當我們想要獲取被包裝函式的引數(argument )或源**(source code)時,同樣不能得到我們想要的結果。

import

inspect

def(

):...

deffunction

(arg1

,arg2

):pass

>>>

print

(inspect

.getargspec

(function

))argspec

(args

=,varargs

='args'

,keywords

='kwargs'

,defaults

=none

)>>>

print

(inspect

.getsource

(function

))@functools

.wraps()

def(*

args,**

kwargs

):return

(*args,**

kwargs

)class

class

(object

):@classmethod

defcmethod

(cls

):pass

traceback

(most recent call 

last

):file"",

line 1,

infile"",

line 3,

inclass

file"",

line 2,

infile

".../functools.py"

,line 33,

insetattr(,

attr

,getattr(,

attr

))attributeerror

:'classmethod'

object

has 

noattribute 

'__module__'

然而,在python3下執行,另乙個問題出現了:

class

class

(object

):@classmethod

defcmethod

(cls

):pass

>>>

class

.cmethod

()traceback

(most recent call 

last

):file

"classmethod.py"

,line 15,

inclass

.cmethod

()file

"classmethod.py"

,line 6,

inreturn

(*args,**

kwargs

)typeerror

:'classmethod'

object

isnot

callable

這是因為包裝器認定被包裝的函式(@classmethod )是可以直接被呼叫的,但事實並不一定是這樣的。被包裝的函式實際上可能是描述符(descriptor ),意味著為了使其可呼叫,該函式(描述符)必須被正確地繫結到某個例項上。關於描述符的定義,可以參考

儘管大家實現裝飾器所用的方法通常都很簡單,但這並不意味著它們一定是正確的並且始終能正常工作。

如同上面我們所看到的,functools.wraps() 可以幫我們解決__name__ 和__doc__ 的問題,但對於獲取函式的引數(argument)或源**( source code )則束手無策。

以上問題,wrapt都可以幫忙解決,詳細用法可參考其官方文件:

Python 裝飾器使用過程中的誤區

大家都知道裝飾器是乙個很著名的設計模式,經常被用於aop 面向切面程式設計 的場景,較為經典的有插入日誌,效能測試,事務處理,web許可權校驗,cache等。python語言本身提供了裝飾器語法 典型的裝飾器實現如下 def function pass 實際上是python2.4才提出的語法糖,針對...

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來包裹的...