一文詳解如何創建自己的Python裝飾器

python裝飾器在平常的python編程中用到的還是很多的,在本篇文章中我們先來介紹一下python中最常使用的@staticmethod裝飾器的使用。

之後,我們會使用兩種不同的方式來創建自己的自定義python裝飾器以及如何在其他地方進行調用。

1、@staticmethod

@staticmethod是python開發者經常用來在一個類中聲明該函數是一個靜態函數時使用到的裝飾器,比如創建一個HelloWorld的python類,並且在其中使用該靜態裝飾器聲明其中的函數。

class HelloWorld():
    def __init__(self):
        super(HelloWorld, self).__init__()

    @staticmethod
    def print_hello_world():
        print('welcome to hello world!')

@staticmethod裝飾器一般是對於一些公共的函數,或是工具函數之類的函數進行聲明,聲明之後就不會將當前python類中的初始化變量信息等傳入到該函數中,可以看到print_hello_world函數並沒有self作為參數變量。

接下來可以在初始化@staticmethod聲明的函數所在的類HelloWorld,並且調用print_hello_world函數。

hello_world = HelloWorld()
hello_world.print_hello_world()

會發現控制臺直接打印出瞭welcome to hello world!這行字符串。

實際上在python中的函數上面加入裝飾器隻是為瞭在執行當前函數的邏輯之前去執行一些我們需要執行的業務功能,這樣的操作我們通過自定義自己的裝飾器也能夠實現同樣的效果。

2、自定義裝飾器

其實,自定義裝飾器的過程也比較簡單,就是我們平常用到的函數或者python類的寫法就能夠實現。

自己實現裝飾器主要有兩種方式,一種是通過class類的方式來實現的,另外一種則是通過python函數嵌套的方式來實現的,下面我們先來通過第一種的方式來實現,也就是通過python類的方式來實現。

python類實現裝飾器

用python類來實現裝飾器時,必須明白一個知識點。python類中實際上默認有一個成員函數__call__,這個成員函數就是這個類被調用時的函數對象,若是需要自定義裝飾器實際上就是在python類的__call__函數中來實現裝飾器主要業務邏輯實現的。

class print_message(object):
    def __init__(self, function_):
        self.function_ = function_

    def __call__(self):
        # TODO:這裡實際上是對傳入的函數返回值進行的裝飾,可以理解成是一種回調。
        print('裝飾器,{}'.format(self.function_()))

註意:在下面這行代碼塊中一定要註意self.function_是一個函數對象,而self.function_()是一個函數返回值得效果。

print('裝飾器,{}'.format(self.function_()))

這樣,我們通過python類就已經實現瞭python裝飾器的效果,使用一個函數來試驗一下效果。

@print_message
def hello_world():
    return 'hello world!'

hello_world()

調用使用瞭@print_message裝飾器的函數,它會返回我們預期的一個函數結果的打印。

# 裝飾器,hello world!

python函數嵌套實現裝飾器

上面的操作過程是通過重新定義瞭一個python類來實現裝飾器的效果的,這裡再使用函數嵌套的方式來實現。

因為,我們都知道在python中函數中再可以嵌套函數的,在函數中嵌套一個函數時上層的函數相對於子函數來說就是它的一個父級對象。

@print_message2
@print_message
def hello_world3():
    return 'hello world!'

hello_world3()

# 裝飾器,hello world!
# 裝飾器2,None

使用函數嵌套的方式同樣實現瞭函數的裝飾器的效果,那麼思考一下若是有兩個裝飾器可以在同一個函數中使用嗎?

多個裝飾器調用

話不多說,為瞭證明兩個裝飾器能不能放到一個函數上面使用,我們直接試一下效果如何。

@print_message2
@print_message
def hello_world3():
    return 'hello world!'

hello_world3()

# 裝飾器,hello world!
# 裝飾器2,None

從返回結果來看,首先是兩個裝飾器都是執行瞭,從數據結果打印的順序來看自定義的裝飾器的執行順序應該是從距離函數最近的裝飾器開始執行的,也就是從下往上的順序挨個執行該函數上面的裝飾器的.

另外,裝飾器2的結果為None,這是為什麼呢?

因為,第一個裝飾器執行的時候,它的參數應該是hello_world函數本身,但是當第二個裝飾器執行的時候第一個裝飾器並沒有返回結果知識做瞭打印,這個時候第二個裝飾器接收到的參數自然就是None瞭。

3、帶參數的裝飾器

說實話帶參數的裝飾器在python中我見到的不多,不多在java中幾乎隻要是裝飾器都是可以加參數執行的。

還是來介紹一下,算是屬於擴展知識吧,既然已經看到瞭這裡,不妨再多掌握個小技能吧,哈哈~

我們使用pytgon嵌套的函數功能來實現這個帶參數的裝飾器吧,個人覺得這種方便一些。

def header(message):
    def decorator(function_):
        def wrapper():
            return '帶參數的裝飾器,參數:{0},{1}'.format(message, function_())
        return wrapper
    return decorator

@header('Python 集中營')
def hello_world4():
    return 'hello world!'

print(hello_world4())

# 帶參數的裝飾器,參數:Python 集中營,hello world!

OK,帶參數的裝飾器果然生效瞭,給@header加上參數@header(‘Python 集中營’),上面裝飾器直接使用三層函數的嵌套來實現的。

第一層函數參數是我們需要自定義給裝飾器傳入的參數,第二層則是傳入的已經添加瞭裝飾器的函數本身,到瞭第三層才是真正的處理裝飾器自己的業務邏輯的。

到此這篇關於一文詳解如何創建自己的Python裝飾器的文章就介紹到這瞭,更多相關Python裝飾器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: