裝飾器的兩三事

裝飾器作爲Python的語法糖,現在應該已經作爲必修知識點了,這一篇是我對於裝飾器的一些略微一點點深入思考後,寫的一篇總結筆記,歡迎大家討論

  • 簡單說兩句裝飾器
       裝飾器其實在版本迭代和代碼重用上,有很明顯的作用,但是他的語法形式,其實有一定的獨特性,所以很多小夥伴對他只是一知半解。
       其實並沒有這麼的複雜,這裏我就給大家拆開了,一步一步的來研究下裝飾器到底是怎麼玩的。
    

廢話不多說,開搞

def func_1(f):
    """
    這是一個有內部函數的函數
    :param f: 參數f是一個可執行的函數 
    :return: 返回內部函數的地址
    """
    def inner():
        """
        這是一個內部函數,執行f()並返回f()的執行結果,f在上面
        :return:  返回值爲函數f的執行結果
        """
        print('this is func1')
        return f()
    return inner

沒問題,我們測試一下

# 這是一個簡單的函數
def func_2():
    print('func_2')


# 獲得內部函數
test_func = func_1(func_2)  # test_func == inner

test_func()  # == inner()

# this is func1
# func_2

結果ok,如果有小夥伴不明白爲什麼,請一定好好的找一個python教程看一下
好了接下來,我要給我們的測試添加條件
1、不允許修改func_2代碼,把func_2這個函數封版,按照開放封閉原則
2、我要以func_2( ) 的形式得到上面輸出的結果

看了這兩個條件,是不是有點懵,這時候就需要動點小腦筋

  • 條件1說不允許改func_2的代碼,好的,我不改,我給他套殼,這時候我們回頭單單看一下func_1( )函數,這是不是就是給inner函數套了一個殼
  • 條件2說不允許修改func_2的調用方式,好的,我還是用func_2( )去執行,只不過我把func_2指向inner,那最後執行的其實就是inner(已經套殼的func_2)

完美

好!我們一步一步來
第一步:我先來做個殼,起個名字叫做clothes,(就像穿了件衣服)

def clothes(func):
    def inner():
        return func()

    return inner

簡單不

      tips:如果這個還看不懂,請認真複習基礎知識,因爲這是一個對於任何編程語言,基礎架構的理解

第二步:我給這個殼加工一下,以防需要被加殼的函數有參數

def clothes(func):
    def inner(*args, **kwargs):
        return func(*args, **kwargs)

    return inner

這裏有一個知識點,(這個知識點我知識測試過,並沒有查過文檔,但是個人感覺應該沒錯,錯了大佬請拍磚)
*args 如果作爲參數傳遞,他會根據函數聲明的個數進行分解
怎麼理解?
1、*args是不定參數 他是一個tuple
2、*args不能作爲變量來聲明,他是函數參數的一個特定參數
如果函數聲明是func(a,b,c,d),如果我傳給他一個不定參數 *args=(1,2,3,4) 那就會自動去契合,他就會讓a=1,b=2,c=3,d=4
注意:
首先,如果你想用*args去給另一個函數傳參數,請匹配那個函數的參數個數
第二點,由於不能用*args去聲明變量,那*args只能在函數內部傳遞,那就說明,你只能給內部函數傳遞*args
這裏先這樣,大家可以自己嘗試下
繼續
第三步:讓殼去做點自己想做的事情

def clothes(func):
    def inner(*args, **kwargs):
        print('I am a cloth')
        return func(*args, **kwargs)

    return inner

第四步:我們給函數套殼

def func_2(str1):
    print(str1)

func_2 = clothes(func_2)
func_2('111')
# I am a cloth
# 111

這時候,func_2已經被套殼了,func_2 == inner
套殼完成!
第一次看可能有點繞,我給大家往白了說,func_2 就是用來獲取clothes函數的返回值,那如果返回是個int呢?

def clothes(func):
    def inner(*args, **kwargs):
        print('I am a cloth')
        return func(*args, **kwargs)

    return 1  # int


func_2 = clothes(func_2)
print(func_2)
# 1

這麼一看是不是就看明白了

這就是裝飾器的原理,並且裝飾器給了我們一個更方便的語法

def clothes(func):
    def inner(*args, **kwargs):
        print('I am a cloth')
        return func(*args, **kwargs)

    return inner


@clothes
def func_2(a):
    print(a)


func_2(111)

@clothes就是裝飾器,把他按在一個函數之上,就代表要用下方函數地址作爲參數,傳遞給裝飾器函數,然後返回再返回給被裝飾的函數(也就是func_2)
這時候你再調用func_2函數就會達到,不修改函數內部,也不修改函數調用方法,就能修改函數功能的作用

基本功能做完,我們再加深一下,能不能給inner函數傳個參數
上面我是打印了一句話 print(‘I am a cloth’) 這次我想打印 print(data) data是個變量
我先給代碼,大家先結合上面的原理看一看

def out(data):
    def clothes(func):
        def inner(*args, **kwargs):
            print(data)
            return func(*args, **kwargs)

        return inner
    return clothes


@out("abcd")
def func_2(a):
    print(a)

我給個過程提示:@out(“abcd”)得拆開
@+out(“abcd”)
1、tmp_func = out(“abcd”)
2、@tmp_func
理解了吧
@看做一個運算符,右邊如果還是一個需要進行運算的結果,類似 int(str(‘a’))

好了,就這樣吧,其實裝飾器之前我有所瞭解,但是原理上還是有點問題,所以拖了好久。如果有還有問題,歡迎討論

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