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

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

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

二、什么是裝飾器

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

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

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

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

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

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

舉個(gè)例子:

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

四、最簡(jiǎn)單的一種自定義裝飾器

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

最常被用來(lái)舉例的場(chǎng)景:計(jì)算某個(gè)函數(shù)的運(yùn)行耗時(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)在需要你再寫一個(gè)函數(shù),也是計(jì)算其的耗時(shí),你難道還有在寫一遍嗎?
所以我們可以把重復(fù)的代碼剝離出來(lái),以往的做法可能是抽取公共方法,但是這種邏輯你會(huì)發(fā)現(xiàn)有點(diǎn)無(wú)從下手,重復(fù)的代碼在你的邏輯前后,這個(gè)時(shí)候裝飾器的作用就出來(lái)了。

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

感覺有點(diǎn)不錯(cuò)。

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

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

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ù)的情況

就是再使用一個(gè)帶參數(shù)的函數(shù),將裝飾器再做一層封裝,返回一個(gè)裝飾器函數(shù)。在裝飾器函數(shù)中就可以使用這個(gè)傳進(jìn)來(lái)的參數(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ù)做了封裝,透出一個(gè)參數(shù)用來(lái)控制是否執(zhí)行打印語(yǔ)句。
foofoo_copy分別傳入兩種參數(shù)值來(lái)測(cè)試一下是否符合預(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)該對(duì)裝飾器有一個(gè)大概的了解,想要更深的去了解,可以多利用搜索引擎。

感謝:whyaza的分享

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容

  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個(gè)常見概念。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,827評(píng)論 0 27
  • Python 是一門極簡(jiǎn)的語(yǔ)言,語(yǔ)言簡(jiǎn)潔學(xué)習(xí)起來(lái)也是相當(dāng)輕松的,但是依然有一些高級(jí)技巧,例如裝飾器、協(xié)程、并發(fā),會(huì)...
    妄心xyx閱讀 1,625評(píng)論 0 23
  • 部分細(xì)節(jié)自己改了點(diǎn),也加了點(diǎn)自己例子,基本上屬于轉(zhuǎn)載。轉(zhuǎn)載出處:https://my.oschina.net/le...
    洛克黃瓜閱讀 1,994評(píng)論 0 3
  • 陸蕓汐 美麗的敕勒川位于連綿起伏的陰山腳下。 那里的天空無(wú)邊無(wú)際,碧藍(lán)碧藍(lán)的。你看那些白云像小船、大樹...
    空中飛翔的燕子閱讀 330評(píng)論 0 0
  • 又是一個(gè)值班日,早晨從家出來(lái)時(shí)爍爍可愛的笑容很暖心
    易如人生閱讀 118評(píng)論 0 0