Python裝飾器介紹

1、問題提出

希望在不修改原函數的情況下,對函數進行擴展。

2、問題解決

  • 引入裝飾器
# 創建幾個函數
def add(a , b):
    '''
        求任意兩個數的和
    '''
    r = a + b
    return r

def mul(a , b):
    '''
        求任意兩個數的積
    '''
    r = a * b
    return r    

# 希望函數可以在計算前,打印開始計算,計算結束後打印計算完畢
# 我們可以直接通過修改函數中的代碼來完成這個需求,但是會產生以下一些問題
#   ① 如果要修改的函數過多,修改起來會比較麻煩
#   ② 並且不方便後期的維護
#   ③ 並且這樣做會違反開閉原則(OCP)
# OCP:程序的設計,要求開放對程序的擴展,要關閉對程序的修改

r = add(123,456)
print(r)

在不修改原函數的情況下,來對函數進行擴展。只需要根據現有的函數,來創建一個新的函數

def fn():
    print('我是fn函數....')

def fn2():
    print('函數開始執行~~~')
    fn()
    print('函數執行結束~~~')

fn2()

此時就達到了對fn函數的一個擴展

對第一個加法示例進行擴展:

def new_add(a,b):
    print('計算開始~~~')
    r = add(a,b)
    print('計算結束~~~')
    return r

r = new_add(111,222)    
print(r)

上述方式,完成在不修改源代碼的情況下對函數進行擴展。

但是,這種方式要求每擴展一個函數就要手動創建一個新的函數,實在是太麻煩了。

爲了解決這個問題,我們創建一個函數,讓這個函數可以自動的幫助我們生產函數

  • 使用裝飾器

每擴展一個函數就可以手動創建一個新的函數,但是這個方式實在是太麻煩了。爲解決這個問題,我們可以創建一個函數,讓這個函數可以自動的幫助我們生產函數

接下來就介紹一下這個自動生成函數的函數怎麼寫:

因爲我們在擴展的時候,不同的函數可能攜帶的參數不同,類型不同或者數量不同導致每次都要修改新函數的類型,所以這裏介紹一下*args 這種通用的用法解決該問題。

def begin_end(old):
    '''
用來對其他函數進行擴展,使其他函數可以在執行前打印開始執行,執行後打印執行結束

        參數:
            old 要擴展的函數對象
    '''
    # 創建一個新函數
    def new_function(*args , **kwargs):
        print('開始執行~~~~')
        # 調用被擴展的函數
        result = old(*args , **kwargs)
        print('執行結束~~~~')
        # 返回函數的執行結果
        return result

    # 返回新函數        
    return new_function

f = begin_end(fn)
f2 = begin_end(add)
f3 = begin_end(mul)

# r = f()
# r = f2(123,456)
r = f3(123,456)
print(r)

像begin_end()這種函數我們就稱它爲裝飾器(舊函數作爲一個參數傳進去,返回一個新函數)。

通過裝飾器,可以在不修改原來函數的情況下來對函數進行擴展。(在開發中,我們都是通過裝飾器來擴展函數功能的。)

  • 裝飾器的典型用法
def fn3(old):
    '''
        用來對其他函數進行擴展,使其他函數可以在執行前打印開始執行,執行後打印執行結束

        參數:
            old 要擴展的函數對象
    '''
    # 創建一個新函數
    def new_function(*args , **kwargs):
        print('fn3裝飾~開始執行~~~~')
        # 調用被擴展的函數
        result = old(*args , **kwargs)
        print('fn3裝飾~執行結束~~~~')
        # 返回函數的執行結果
        return result

    # 返回新函數        
    return new_function

@fn3
@begin_end
def say_hello():
    print('大家好~~~')

say_hello()

此處先裝飾了離函數最近的begin_end,又在外部裝飾了fn3裝飾器。如果調換了位置,裝飾順序就不同了。

總結:在定義函數時,可以通過@裝飾器,來使用指定的裝飾器,來裝飾當前的函數。

可以同時爲一個函數指定多個裝飾器,這樣函數將會按照從內向外的順序被裝飾

3、參考

裝飾器的使用 :https://developer.aliyun.com/article/750028?spm=a2c6h.12873639.0.0.5e3f65cah9iK90&groupCode=python

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章