一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

python筆記35-裝飾器

 上海悠悠 2021-05-27

前言

python裝飾器本質(zhì)上就是一個(gè)函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動(dòng)的前提下增加額外的功能,裝飾器的返回值也是一個(gè)函數(shù)對(duì)象。
很多python初學(xué)者學(xué)到面向?qū)ο箢惡头椒ㄊ且坏来罂?,那么python中的裝飾器是你進(jìn)入Python高級(jí)語(yǔ)法大門的一道坎。

計(jì)算函數(shù)運(yùn)行時(shí)間

假設(shè)你寫(xiě)了幾個(gè)函數(shù),有一天領(lǐng)導(dǎo)心血來(lái)潮說(shuō),你把每個(gè)函數(shù)的運(yùn)行時(shí)長(zhǎng)(結(jié)束時(shí)間-開(kāi)始時(shí)間)統(tǒng)計(jì)下,作為一個(gè)python實(shí)習(xí)生的你可能會(huì)這樣寫(xiě)

原始函數(shù)

import time def func_a(): print("hello") time.sleep(0.5) def func_b(): print("world") time.sleep(0.8) if __name__ == '__main__': func_a() func_b()

添加運(yùn)行時(shí)長(zhǎng)

作為一個(gè)實(shí)習(xí)生的你,可能想到的解決辦法如下

import time def func_a(): start = time.time() print("hello") time.sleep(0.5) end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (end-start)) def func_b(): start = time.time() print("world") time.sleep(0.8) end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (end-start)) if __name__ == '__main__': func_a() func_b()

運(yùn)行結(jié)果:

hello 運(yùn)行時(shí)長(zhǎng):0.5009 秒 world 運(yùn)行時(shí)長(zhǎng):0.8008 秒

上面的代碼雖然滿足了領(lǐng)導(dǎo)的要求,但是如果你寫(xiě)的函數(shù)很多的話,每個(gè)函數(shù)都這樣去添加,會(huì)顯得代碼很臃腫,有很多重復(fù)代碼。
有一天你邊上的一個(gè)python老司機(jī)看了下你的代碼,給你指了條路:裝飾器

函數(shù)裝飾器

裝飾器可以寫(xiě)成函數(shù)式裝飾器,也可以寫(xiě)成一個(gè)類裝飾器,先從簡(jiǎn)單的函數(shù)裝飾器開(kāi)始學(xué)習(xí)。
python裝飾器本質(zhì)上就是一個(gè)函數(shù),它可以讓其他函數(shù)在不需要做任何代碼變動(dòng)的前提下增加額外的功能,裝飾器的返回值也是一個(gè)函數(shù)對(duì)象。

runtime函數(shù)就是一個(gè)裝飾器了,它對(duì)原函數(shù)做了包裝并返回了另外一個(gè)函數(shù),額外添加了一些功能。在函數(shù)上方使用@語(yǔ)法糖就可以調(diào)用這個(gè)裝飾器了

import time def runtime(func): def wrapper(): start = time.time() f = func() # 原函數(shù) end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (end-start)) return f return wrapper @runtime def func_a(): print("hello") time.sleep(0.5) @runtime def func_b(): print("world") time.sleep(0.8) if __name__ == '__main__': func_a() func_b()

運(yùn)行結(jié)果

hello 運(yùn)行時(shí)長(zhǎng):0.5001 秒 world 運(yùn)行時(shí)長(zhǎng):0.8001 秒

函數(shù)帶參數(shù)裝飾器

上面的runtime就是一個(gè)簡(jiǎn)單的裝飾器模型了,但并不強(qiáng)壯,如果函數(shù)里面帶有參數(shù),那就不管用了,并且函數(shù)的參數(shù)是不固定的,這時(shí)候就需要用到*args,**kwargs兩兄弟了

import time def runtime(func): def wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函數(shù) end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (end-start)) return f return wrapper @runtime def func_a(a): print("hello"+a) time.sleep(0.5) @runtime def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")

類裝飾器

關(guān)于__call__方法,不得不先提到一個(gè)概念,就是可調(diào)用對(duì)象(callable),我們平時(shí)自定義的函數(shù)、內(nèi)置函數(shù)和類都屬于可調(diào)用對(duì)象,
但凡是可以把一對(duì)括號(hào)()應(yīng)用到某個(gè)對(duì)象身上都可稱之為可調(diào)用對(duì)象,判斷對(duì)象是否為可調(diào)用對(duì)象可以用函數(shù) callable。
如果在類中實(shí)現(xiàn)了__call__方法,那么實(shí)例對(duì)象也將成為一個(gè)可調(diào)用對(duì)象

import time class runtime(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): start = time.time() f = self.func(*args, **kwargs) # 原函數(shù) end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (end-start)) return f @runtime def func_a(a): print("hello"+a) time.sleep(0.5) @runtime def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")

裝飾器帶參數(shù)

快到年底了,領(lǐng)導(dǎo)說(shuō)運(yùn)行的速度先不要太快了,讓客戶先加錢,然后再以正常的速度顯示,那么現(xiàn)在的需求是讓每個(gè)函數(shù)的運(yùn)行時(shí)間加50%,該如何實(shí)現(xiàn)呢?
這就到了裝飾器的高級(jí)語(yǔ)法,裝飾器也需要帶上參數(shù)了

函數(shù)裝飾器

import time def runtime(slowly=1): def wrapper(func): def inner_wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函數(shù) end = time.time() t = end-start time.sleep((slowly-1)*t) # 延遲效果 new_end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (new_end-start)) return f return inner_wrapper return wrapper @runtime(1.5) def func_a(a): print("hello"+a) time.sleep(0.5) @runtime(1.5) def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")

類裝飾器

import time class runtime(object): def __init__(self, slowly=1): self.slowly = slowly def __call__(self, func): def wrapper(*args, **kwargs): start = time.time() f = func(*args, **kwargs) # 原函數(shù) end = time.time() t = end-start time.sleep((self.slowly-1)*t) # 延遲效果 new_end = time.time() print("運(yùn)行時(shí)長(zhǎng):%.4f 秒" % (new_end-start)) return f return wrapper @runtime(1.5) def func_a(a): print("hello"+a) time.sleep(0.5) @runtime(1.5) def func_b(b, c="xx"): print("world"+b+c) time.sleep(0.8) if __name__ == '__main__': func_a("a") func_b("b", c="xxx")

使用場(chǎng)景

用哪些地方需要使用裝飾器呢?

  • 如果你用過(guò)locust,設(shè)置權(quán)重會(huì)用到@task(1),
  • 如果你用過(guò)pytest框架,使用fixture功能的時(shí)候經(jīng)常會(huì)用到@pytest.fixture(scope="function")
  • allure里面可以添加測(cè)試步驟 @allure.step('修改購(gòu)物車')
  • 被大量使用于Flask和Django web框架中,檢查是否被授權(quán)去使用一個(gè)web應(yīng)用的端點(diǎn)(endpoint)。如 @login_required
  • 也可以自己寫(xiě)個(gè)裝飾器添加日志

2019年《python3自動(dòng)化UI+接口》課程5月25-7月27開(kāi)課
主講老師:上海-悠悠
上課方式:QQ群視頻在線教學(xué)
上課時(shí)間:每周六、周日晚上20:30-22:30
報(bào)名費(fèi):2000

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    搡老熟女老女人一区二区| 欧美一区二区黑人在线| 欧美欧美欧美欧美一区| 欧洲亚洲精品自拍偷拍| 蜜臀人妻一区二区三区| 国产一区二区三中文字幕 | 精品人妻一区二区三区在线看| 成人免费视频免费观看| 欧美激情一区二区亚洲专区| 日韩精品综合免费视频| 亚洲男人的天堂久久a| 99久久精品午夜一区| 欧美成人黄色一级视频| 初尝人妻少妇中文字幕在线| 黄色av尤物白丝在线播放网址 | 麻豆一区二区三区在线免费| 少妇人妻无一区二区三区| 亚洲性日韩精品一区二区| 国产精品欧美激情在线播放| 亚洲国产天堂av成人在线播放 | 国产精品一区二区传媒蜜臀| 91在线国内在线中文字幕| 最近最新中文字幕免费| 亚洲精品中文字幕熟女| 国产精品午夜一区二区三区 | 亚洲欧美中文字幕精品| 中文字幕一区二区熟女| 欧美一区二区三区五月婷婷| 国产一级一片内射视频在线| 最新国产欧美精品91| 中文字幕日产乱码一区二区| 亚洲精品国产美女久久久99| 亚洲成人免费天堂诱惑| 男人和女人干逼的视频| 99久久精品免费看国产高清| 国产精品一区二区视频大全| 欧美成人免费夜夜黄啪啪| 91一区国产中文字幕| 日本人妻熟女一区二区三区| 激情中文字幕在线观看| 亚洲视频一级二级三级|