Python的裝飾器原來是這麼用的

公衆號:pythonislover

Python的裝飾器,是一個Python中一個比較難以理解的知識點, 今天我試試說一說,說的如果不好,請見諒。

裝飾器,從字面意思來說,就是修飾一個事物的,在Python裏面的作用就是讓一個已經存在的函數擁有一個以前沒有的功能。裝飾器本質上還是一個函數,知識他的功能是爲其他函數添加新功能。

那有人會說,我在原來的函數裏面加一些代碼,也可以實現啊,爲什麼還要搞個裝飾器來增加功能呢? 當然,如果你給一個函數加個功能,是可以加代碼, 但是如果是讓你給100個函數代碼塊加一個相同的功能呢? 一個個改代碼嗎? 你會奔潰的。

下面說說一個裝飾器要實現,要符合一定的規則,就是兩個不改動
1.不改動被裝飾函數的源代碼
2.不改動被修飾函數的調用方式

就是你加沒加這個裝飾器,函數要按照原樣來調用

下面說說裝飾器到底怎麼寫,怎麼用,上面說到裝飾器也是一個函數,但是這個函數和普通的函數不太一樣,他是一個高階函數,那我們給裝飾器大概下個定義

裝飾器:一個可以給別的函數添加新功能的高階函數(當然現在還是不完整的定義)

下面介紹下什麼是高階函數。

高階函數: 一個可以接受函數爲參數或者能reture 一個函數的函數就是高階函數

是不是有點繞,舉個例子

def f1():  
    print('普通函數')

def f2(func):  #f2函數的參數是一個函數,所以它是一個高階函數
    print('高階函數1')
    f1()

def f3(func): #f3函數的返回值是一個函數,所以它是一個高階函數
    print('高階函數2')
    return func

f2(f1)
f3(f1)

結果:
高階函數1
普通函數
高階函數2

有點基礎的人可能知道,這個根本就不是裝飾器,騙人的。當然裝飾器不是這麼簡單。

那下面要介紹的一個東西叫嵌套函數,那什麼叫嵌套函數呢? 字面意思應該就知道了,函數裏面套一個子函數

舉個例子:

def outer():
    print('outer')
    def inner():
        print('inner')
    inner()
outer()

結果
outer
inner

下面我們要給裝飾器重新下個定義了。

裝飾器:一個可以給別的函數添加新功能的高階函數+嵌套函數

那麼我們把高階函數+嵌套函數結合在一起看看

一個可以添加一行日誌的裝飾器

def add_log(func):  #一個函數作爲參數,這個函數就是我們要
    def wrapper():
        print('我們要加一些日誌') #要給原函數添加的新功能,這裏就是打印一行日誌,當然可以實現其他複雜的功能
        func()
    return wrapper

#上面可以看到高階函數+嵌套函數的影子吧,加一起就是一個最簡單的裝飾器拉

@add_log  #裝飾器的用法
def f1():
    print('普通函數')

f1()  #調用函數

結果:
#看結果f1裏面只有print一行,但是結果多了一行,就是裝飾器的作用
我們要加一些日誌
普通函數

這些裝飾器大概知道上面意思了吧。

下面說說,上面的裝飾器,有沒有沒有上面問題呢?

看看,仔細看看。 看出來了嗎? 看不出來,我說了哦。

上面我們的f1()函數, 沒有參數,是不是,想想如果f1()函數要加參數怎麼辦啊?

def add_log(func):
    def wrapper(name):
        print('我們要加一些日誌')
        func(name)
    return wrapper

@add_log
def f1(name):
    print('普通函數 %s' %name)

f1('python')

有人是不是想這樣實現呢?

當然這樣是可以的,但是我們不要忘了裝飾器的作用,他不是給某一個固定的函數來使用的,假如現在還需要修飾一個f2(name,age), 那怎麼辦啊? 沒辦法,裝飾器的代碼都給你定死了,所以上面這樣寫是不行的。

到底怎麼寫呢?

def add_log(func):
    def wrapper(*args,**kwargs):
        print('我們要加一些日誌')
        func(*args,**kwargs)
    return wrapper

@add_log
def f1(name):
    print('普通函數 %s' %name)

@add_log
def f2(name,age):
    print('我是%s,我%s歲了' %(name,age))

f1('python')
f2('java',10)

結果:
我們要加一些日誌
普通函數 python
我們要加一些日誌
我是java,我10歲了

上面的寫法,是不是可以了,是不是,不管任何函數,任何參數,都OK了,至於args,*kwargs啥意思,大家可以去百度下啊。這裏就不多說了

今天就說這麼多,希望大家對於python的裝飾器有個基本的瞭解。

這裏留個彩蛋,上面的最終的代碼,你覺得還有問題嗎?仔細看,如果能看出來歡迎給我留言,如何看不出來,看我下回分解。

好文推薦:
Python 迭代器與可迭代對象,看不懂你找我 - https://mp.weixin.qq.com/s/uXRHMRSuxg0WEUv3QD1R8w
python正則表達式 - https://mp.weixin.qq.com/s/UR0g8vDBnOqYZVnQRvUFlw
Python的裝飾器原來是這麼用的 - https://mp.weixin.qq.com/s/Ak6RjM-I6JbV1MFmWhU45A
Python的裝飾器原來是這麼用的-續- https://mp.weixin.qq.com/s/A92jI-T0kwYMJF7_YxqC2Q
Python 迭代器與可迭代對象,看不懂你找我 - https://mp.weixin.qq.com/s/uXRHMRSuxg0WEUv3QD1R8w
三分鐘搞懂Python生成器 - https://mp.weixin.qq.com/s/Qv6O3HqiGnoEP0-oS5YGZg
Python GIL - https://mp.weixin.qq.com/s/o8ngXJ5qzVCB2xr_o_ClxQ
看這一篇文章搞懂Python閉包 - https://mp.weixin.qq.com/s/uI7z6OSv-oUqHQqAMUcYPQ
Python中正則表達式的巧妙使用 - https://mp.weixin.qq.com/s/tPScojLeDpEPFALY7jFk3w

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