天天看點

python中的裝飾器、裝飾器模式_裝飾器模式在python中的應用

裝飾器模式:允許向一個現有的對象添加新的功能,同時又不改變其結構。在python中,裝飾器可以是一個函數或者一個類。

在解釋裝飾器模式時,先了解下python中@符号的含義:

1、@符号是python中的一種修飾符,用來修飾函數,修飾符必須出現在函數定義的前一行,不允許和函數定義在同一行。

2、一個修飾符就是一個函數,它将修飾的函數作為參數,并傳回修飾後的同名函數或者其他可以調用的類型。

書面解釋比較抽象,來看一個例子:

import time

def get_current_time(func):

print time.time()

return func()

@get_current_time

def sum():

print "sum 函數求和"

運作結果:

1531305351.73

sum 函數求和

其中@符号修飾了sum函數,相當于将sum函數作為參數傳入了get_current_time函數,然後執行了get_current_time函數的主體流程。

python中裝飾器模式應用分為:

1、函數裝飾器,可以了解為裝飾器為某個定義的函數。

2、帶參數的裝飾器,可以了解為裝飾器函數可以包含參數傳遞。

3、類裝飾器,可以了解為裝飾器為一個定義的類,這種情況一般應用較少。

python内置裝飾器有@staticmathod、@classmethod、@property,分别對應靜态方法,類方法,類屬性。

先看函數裝飾器:

import logging

def get_logging(func):

def wrapper(*args, **kwargs):

logging.warn("this is debug log :%s"% func.__name__)

return func(*args, **kwargs)

return wrapper

@get_logging

def test_func():

print "this is a test function"

if __name__ == '__main__':

test_func()

輸出結果為:

this is a test function

WARNING:root:this is debug log :test_func

函數get_logging就是裝飾器,它将執行真正業務函數test_func包裹在函數中,看起來test_func被get_logging裝飾了。簡單解釋下*args和**kwargs,*args作為函數參數時,是一種可變參數,可以傳一個或者多個值,如果定義函數test(*args),那麼調用test時,test(1,2,3,None,5),此時的args擷取到的值為一個元組tuple,為(1,2,3,None,5);同理**args作為函數參數時,也是一種可變參數,差別是這裡傳遞的值是以鍵值對呈現的,如果定義函數test(**args),那麼調用test時,test(a = 1,b = 2,c = 3),此時的args擷取到的值為一個字典dict,值為{'a':1,'b':2,'c':3}。

帶參數的裝飾器:

裝飾器還有更大的甯活性,比如帶參數的裝飾器。裝飾器的文法允許我們在調用時,提供其他參數,比如get_logging(flag),這樣就為裝飾器的執行提供了更大的靈活性。

比如将上面的例子稍微修改下:

import logging

def use_decorator(level):

def get_logging(func):

def wrapper(*args, **kwargs):

if level == "warn":

logging.warn("this is warn log :%s"% func.__name__)

if level == "error":

logging.error("this is error log :%s" % func.__name__)

return func(*args, **kwargs)

return wrapper

return get_logging

@use_decorator(level = "error")

def test_func():

print "this is a test function"

if __name__ == '__main__':

test_func()

輸出結果為:

ERROR:root:this is error log :test_func

this is a test function

給原來的get_logging外層加了一個use_decorator函數,實作函數參數的傳遞與判斷。use_decorator是一個允許帶參數的裝飾器,實際是對原有裝飾器的一個函數封裝,并傳回一個裝飾器。

類裝飾器:

相比如函數裝飾器,類裝飾器具有靈活度大、高内聚、封裝性等優點,使用類裝飾器還可以依靠内部的__call__方法,當使用@形式将裝飾器附加到函數上時,就會調用此方法。

比如下面的例子:

class use_decorator(object):

def __init__(self, func):

self.func = func

def __call__(self, *args, **kwargs):

print "start execute decorator "

self.func()

print "end execute decorator "

@use_decorator

def test_func():

print "this is a test function"

if __name__ == '__main__':

test_func()

執行結果為:

start execute decorator

this is a test function

end execute decorator

相比于第一種函數裝飾器,類裝飾器是将原始方法傳遞到初始化__init__函數中,然後調用預設的__call__方法去完成裝飾器的執行邏輯。

最後我們看看多層裝飾器的嵌套使用,例子如下:

def decorator_A(func):

print "decorator A is call"

return func

def decorator_B(func):

print "decorator B is call"

return func

def decorator_C(func):

print "decorator C is call"

return func

@decorator_A

@decorator_B

@decorator_C

def test_func():

print "this is a test function"

if __name__ == '__main__':

test_func()

執行結果為:

decorator C is call

decorator B is call

decorator A is call

this is a test function

從結果分析,先是執行了最裡層裝飾器函數decorator_C,然後将傳入的方法test_func傳回給了外層裝飾器decorator_B,同樣執行完decorator_B後将被裝飾的方法作為參數傳遞給了裝飾器decorator_A,最終完成被裝飾器函數test_func的執行。整個過程相當于執行了:decorator_A(decorator_B(decorator_C(test_func)))。