Python 裝飾器的學(xué)習(xí)筆記

一、作為一個測試為什么學(xué)裝飾器?

在使用python寫東西的時候,可能會遇到并使用到裝飾器,為了加深“功力”還是很有必要去學(xué)習(xí)一下的。不能只知道使用,完全去“復(fù)制”別人的代碼,還是要知道為什么要這么寫的。以后可能親自去實現(xiàn)一個裝飾器的機會并不多,所以也許并不需要能熟練的去寫一個裝飾器。為了滿足“好奇心”了解一下還是很有不錯的學(xué)習(xí)過程。

二、什么是裝飾器

裝飾器本質(zhì)上是一個python函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能。

這是我查閱資料時,看到比較多的描述,所以裝飾器它是:

  1. 它也是一個函數(shù)
  2. 能夠給修飾的代碼提供額外的功能

這讓我想到了java中的“注解”,當(dāng)然也許他們的實現(xiàn)方式不同。(若類比失當(dāng),大佬勿噴,留言指正)
都類似@xxxx的語法糖寫法。

三、 典型的應(yīng)用場景

一般應(yīng)用于抽離出與函數(shù)邏輯無關(guān)的可重用的代碼,比如插入日志、性能測試、事務(wù)處理、緩存、權(quán)限驗證等場景。

舉個例子:

  1. 在flask框架中,來做路由的定義
from flask import Flask
 
app = Flask(__name__)
 
@app.route('/')
def hello_world():
    return 'Hello World!'
 
if __name__ == '__main__':
    app.run()
  1. 在單元測試中,可以用來忽略某些測試case
@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
    def test_not_run(self):
        pass

四、最簡單的一種自定義裝飾器

裝飾器無參數(shù),被裝飾的函數(shù)也是無參數(shù)的,是最基本的一種自定義參數(shù)。

最常被用來舉例的場景:計算某個函數(shù)的運行耗時

  1. 先看下不用裝飾器的寫法吧
import time
def foo():
    for i in range(10):
        print('....')
        time.sleep(0.5)


start_time = time.time()
foo()
end_time = time.time()
print('spend time is {}'.format(end_time - start_time))

不多介紹了吧。
但是現(xiàn)在需要你再寫一個函數(shù),也是計算其的耗時,你難道還有在寫一遍嗎?
所以我們可以把重復(fù)的代碼剝離出來,以往的做法可能是抽取公共方法,但是這種邏輯你會發(fā)現(xiàn)有點無從下手,重復(fù)的代碼在你的邏輯前后,這個時候裝飾器的作用就出來了。

import time

def show_time(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print('spend time is {}'.format(end_time - start_time))

    return wrapper


@show_time
def foo():
    for i in range(5):
        print('*****')
        time.sleep(0.5)


@show_time
def foo_copy():
    for i in range(5):
        print('+++++')
        time.sleep(0.5)


foo()
foo_copy()

看一下打印結(jié)果感受一下:

*****
*****
*****
*****
*****
spend time is 2.5002501010894775
+++++
+++++
+++++
+++++
+++++
spend time is 2.5002498626708984

感覺有點不錯。

五、被裝飾函數(shù)帶參數(shù)的裝飾器

本例是被裝飾的函數(shù)帶兩個參數(shù),而裝飾器函數(shù)不帶參數(shù)的,有點簡單,代碼如下:

import time


def show_time(func):
    def wrapper(a, b):
        start_time = time.time()
        func(a, b)
        end_time = time.time()
        print('spend time is {}'.format(end_time - start_time))

    return wrapper


@show_time
def foo(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


foo(1, 2)

打印結(jié)果:

a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5002501010894775

六、裝飾器帶參數(shù)的情況

就是再使用一個帶參數(shù)的函數(shù),將裝飾器再做一層封裝,返回一個裝飾器函數(shù)。在裝飾器函數(shù)中就可以使用這個傳進(jìn)來的參數(shù),這種函數(shù)好像也叫做閉包函數(shù)。(才疏學(xué)淺,不做解釋)

舉例代碼:

import time


def is_show_time(is_show=True):
    def show_time(func):
        def wrapper(a, b):
            start_time = time.time()
            func(a, b)
            end_time = time.time()
            if is_show is True:
                print('spend time is {}'.format(end_time - start_time))

        return wrapper

    return show_time


@is_show_time(is_show=True)
def foo(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


@is_show_time(is_show=False)
def foo_copy(a, b):
    for i in range(5):
        print('a + b = ' + str(a + b))
        time.sleep(0.5)


foo(1, 2)
foo_copy(3, 4)

is_show_time函數(shù)將我們上面例子中的show_time函數(shù)做了封裝,透出一個參數(shù)用來控制是否執(zhí)行打印語句。
foofoo_copy分別傳入兩種參數(shù)值來測試一下是否符合預(yù)期。
打印結(jié)果如下:

a + b = 3
a + b = 3
a + b = 3
a + b = 3
a + b = 3
spend time is 2.5
a + b = 7
a + b = 7
a + b = 7
a + b = 7
a + b = 7

Process finished with exit code 0

七、后記

介紹上面這些,應(yīng)該對裝飾器有一個大概的了解,想要更深的去了解,可以多利用搜索引擎。

感謝:whyaza的分享

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容