python裝飾器 decotator 詳解

2021-08-10 23:22:12 字數 4029 閱讀 5227

###先來看看乙個列子

def foo():

print '我是lxshen'

foo()

輸出:我是lxshen

這時我想在這個輸出前面再執行一段程式。這時我們首先想到的是以下兩種方法:

方法一:直接在函式中新增

def foo():

print 'hello,'

print '我是lxshen'

foo()

輸出:hello, 我是lxshen

方法二:我再另寫乙個函式,再foo函式中呼叫

def foo():

fee()

print '我是lxshen'

def fee():

print 'hello,'

foo()

輸出:hello, 我是lxshen

這樣一看,你可能會說這兩種方法好像第一種更加方便,那麼我只能呵呵了,由於我這裡只是舉乙個列子,你可以想象要新增的一段**,**量是100行甚至更多,並且要在幾十個函式中新增。那麼這時候你會選擇哪個方法?反正我是選擇第二種,不然會死人的。

###裝飾器

這樣你以為就完了嗎,一般在開發過程中,要遵循開放封閉原則,雖然在這個原則是用的物件導向開發,但是也適用於函式式程式設計,簡單來說,它規定已經實現的功能**不允許被修改,但可以被擴充套件,即:

乙個簡單的裝飾器:
def fee(func):    # 需要傳遞乙個函式

def wrap(): # 如果這個函式需要傳遞引數,那麼所需要引數就寫在這裡

print 'hello,'

return func()

return wrap

def foo():

print '我是lxshen'

f = fee(foo) # f 等價於 wrap

f() # wrap()

輸出:hello, 我是lxshen

函式fee就是裝飾器,它把執行真正業務邏輯**的foo包裹在函式裡面,看起來像bar被use_logging裝飾了。在這個例子中,函式進入和對出是,被稱為乙個橫切面(aspect),這種程式設計方式被稱為面向切面的程式設計(aspect-oriented programming)

使用』語法糖』@

@符號是裝飾器的』語法糖』,在定義函式的時候使用,避免再一次賦值操作

def fee(func):     

def wrap():

print 'hello,'

func()

return wrap

@fee

def foo():

print '我是lxshen'

foo()

輸出:hello, 我是lxshen

foo() 可以理解為:

foo = fee(foo)

# foo先作為引數賦值給func後,foo接收指向fee返回的wrap

foo()

# 呼叫foo(),即等價呼叫wrap()

# 內部函式wrap被引用,所以外部函式的func變數(自由變數)並沒有釋放

# func裡儲存的是原foo函式物件

如果我們有其他的類似函式,我們可以繼續呼叫裝飾器來修飾函式,而不用重複修改函式或者增加新的封裝。這樣,我們就提高了程式的可重複利用性,並增加了程式的可讀性。

####2.被裝飾的函式有引數

def fee(func):

def wrap(gold):

print 'hello,'

func(gold)

return wrap

@fee

def foo(gold):

print gold

print '我是lxshen'

@fee

def faa(gold):

print gold

print '我是xiaoming'

faa('lxshen')

輸出:hello, lxshen 我是xiaoming

在閉包wrap中執行func函式(即執行foo函式),既然func需要乙個引數,那麼閉包warp就需要乙個新增引數。如果還是不理解,可以把 這個例子拆開成『乙個簡單的裝飾器』的樣子來看。

####3.修飾器帶引數

def user(name):

def fee(func):

def wrap(gold):

if name == 'lxshen':

print 'hello,'

elif name == 'xiaoming':

print '你好,'

func(gold)

return wrap

return fee

@user(name='lxshen')

def foo(gold):

print gold

print '我是lxshen'

@user(name='xiaoming')

def faa(gold):

print gold

print '我是xiaoming'

faa('lxshen')

上面的user是允許帶引數的裝飾器。他實際上是對原有裝飾器的乙個函式封裝,並返回乙個裝飾器。我們可以將它理解我乙個含有引數的閉包。

####4.類裝飾器

裝飾器函式其實是這樣乙個介面約束,它必須接受乙個callable物件作為引數,然後返回乙個callable物件。在python中一般callable物件都是函式,但也有例外。只要某個物件重寫了call() 方法,那麼這個物件就是callable的。

class fee(object):

def __init__(self,func):

self._func = func

def __call__(self, name):

print 'hello'

self._func(name)

@fee

def foo(gold):

print gold

print 'lxshen'

輸出:分析:

#1.當用fee來裝作裝飾器對foo函式進行裝飾的時候,首先會建立fee的例項物件

# 並且會把foo這個函式名當做引數傳遞到__init__方法中

# 即在__init__方法中的func變數指向了foo函式體

#2. foo函式相當於指向了用fee建立出來的例項物件

##3. 當在使用foo()進行呼叫時,就相當於讓這個物件(),因此會呼叫這個物件的__call__方法

##4. 為了能夠在__call__方法中呼叫原來foo指向的函式體,所以在__init__方法中就需要乙個例項屬性來儲存這個函式體的引用

# 所以才有了self.__func = func這句**,從而在呼叫__call__方法中能夠呼叫到foo之前的函式體

###總結:

1.什麼時候使用裝飾器?

一般在開發過程中,要遵循開放封閉原則,雖然在這個原則是用的物件導向開發,但是也適用於函式式程式設計,簡單來說,它規定已經實現的功能**不允許被修改,但可以被擴充套件,這時就要使用裝飾器了。

2.使用裝飾器來修飾函式

不改變原有的程式,並且可以新增新的功能

可以提高程式的可重複利用性,並增加了程式的可讀性。

python裝飾器 Python 裝飾器

簡言之,python裝飾器就是用於拓展原來函式功能的一種函式,這個函式的特殊之處在於它的返回值也是乙個函式,使用python裝飾器的好處就是在不用更改原函式的 前提下給函式增加新的功能。一般而言,我們要想拓展原來函式 最直接的辦法就是侵入 裡面修改,例如 這是我們最原始的的乙個函式,然後我們試圖記錄...

python裝飾器 裝飾器

由於函式也是乙個物件,而且函式物件可以被賦值給變數,所以,通過變數也能呼叫該函式。def now print 2015 3 25 f now f 2015 3 25 函式物件有乙個 name 屬性,可以拿到函式的名字 now.name now f.name now 現在,假設我們要增強now 函式的...

python裝飾器原理 Python裝飾器原理

裝飾器 decorator 是物件導向設計模式的一種,這種模式的核心思想是在不改變原來核心業務邏輯 的情況下,對函式或類物件進行額外的修飾。python中的裝飾器由python直譯器直接支援,其定義形式如下 decorator def core service 要理解上述 的含義,我們從自定義函式裝...