Python裝飾器(decorator)定義與用法詳解
本文實例講述了Python裝飾器(decorator)定義與用法。分享給大家供大家參考,具體如下:
什么是裝飾器(decorator)
簡單來說,可以把裝飾器理解為一個包裝函數(shù)的函數(shù),它一般將傳入的函數(shù)或者是類做一定的處理,返回修改之后的對象.所以,我們能夠在不修改原函數(shù)的基礎(chǔ)上,在執(zhí)行原函數(shù)前后執(zhí)行別的代碼.比較常用的場景有日志插入,事務(wù)處理等.
裝飾器
最簡單的函數(shù),返回兩個數(shù)的和
def calc_add(a, b): return a + b calc_add(1, 2)
但是現(xiàn)在又有新的需求,計算求和操作耗時,很簡單,求和前獲取一下時間,求和后再獲取一次,求差即可
import datetime def calc_add(a, b): start_time = datetime.datetime.now() result = a + b end_tiem = datetime.datetime.now() print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs" return result calc_add(1, 2)
現(xiàn)在呢,函數(shù)calc_diff(a, b),計算a-b,也想計算減法操作的時間差,很好辦,把那段代碼復(fù)制過去.但是假如我們現(xiàn)在想編的是一個數(shù)學(xué)函數(shù)庫,各種函數(shù)都想計算其執(zhí)行耗時,總不能一個一個復(fù)制代碼,想個更好的辦法.
我們知道,在Python中函數(shù)也是被視為對象的,可以作為參數(shù)傳遞,那么假如把計算耗時的獨立為一個單獨的函數(shù)calc_spend_time(),然后把需要計算耗時的函數(shù)例如calc_add的引用傳遞給它,在calc_spend_time中調(diào)用calc_add,這樣所有的需要計算耗時的函數(shù)都不用修改自己的代碼了.
def calc_spend_time(func, *args, **kargs): start_time = datetime.datetime.now() result = func(*args, **kargs) end_tiem = datetime.datetime.now() print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs" def calc_add(a, b): return a + b calc_spend_time(calc_add, 1, 1) # calc_spend_time(calc_add, a=1, b=2)
看起來也不錯,負責(zé)計算的函數(shù)不用更改,只需調(diào)用的時候作為參數(shù)傳給計算時間差的函數(shù).但就是這,調(diào)用的時候形式變了,不再是clac(1, 2),而是calc_spend_time(clac_add, 1, 2),萬一calc_add大規(guī)模被調(diào)用,那么還得一處一處找,然后修改過來,還是很麻煩.如果想不修改代碼,就得使clac()和calc_spend_time(clac)效果一樣,那么可以在calc_spend_time()里把傳入的clac包裝一下,然后返回包裝后的新的函數(shù),再把返回的包裝好的函數(shù)賦給clac,那么calc()的效果就和上例calc_spend_time(calc())效果一樣.
import datetime def calc_spend_time(func): def new_func(a, b): start_time = datetime.datetime.now() result = func(a, b) end_tiem = datetime.datetime.now() print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs" return new_func def calc_add(a, b): return a + b calc_add = calc_spend_time(calc_add) calc_add(1, 2)
語法糖
上面的例子就是裝飾器的概念,包裝函數(shù)的函數(shù).事實上上面的例子還可以更精簡
import datetime def calc_spend_time(func): def new_func(a, b): start_time = datetime.datetime.now() result = func(a, b) end_tiem = datetime.datetime.now() print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs" return new_func @calc_spend_time def calc_add(a, b): return a + b calc_add(1, 2)
@calc_spend_time就是語法糖,它的本質(zhì)就是:calc_add = calc_spend_time(calc_add)
無參數(shù)的函數(shù)裝飾器
import datetime def calc_spend_time(func): def new_func(*args, **kargs): start_time = datetime.datetime.now() result = func(*args, **kargs) end_tiem = datetime.datetime.now() print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs" return new_func @calc_spend_time def calc_add(a, b): return a + b @calc_spend_time def calc_diff(a, b): return a - b calc_add(a=1, b=2) calc_diff(1, 2)
注:
*args:把所有的參數(shù)按出現(xiàn)順序打包成list
**kargs:把所有的key=value形式的參數(shù)打包成一個dict
帶參數(shù)的函數(shù)裝飾器
假如我們需要知道函數(shù)的一些額外信息,例如函數(shù)作者,可以通過給裝飾器函數(shù)增加參數(shù)來實現(xiàn).
import datetime
def calc_spend_time(author):
def first_deco(func):
def new_func(*args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
return a + b
@calc_spend_time('author_2')
def calc_diff(a, b):
return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)
Python內(nèi)置裝飾器
Python內(nèi)置的裝飾器有三個:staticmethod,classmethod和property.
staticmethod:把類中的方法定義為靜態(tài)方法,使用staticmethod裝飾的方法可以使用類或者類的實例對象來調(diào)用,不需要傳入self
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
@staticmethod
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
def speak(self, message):
self.say(message)
Human.say(None)
human = Human()
human.speak('hi')
輸出:
I say hello I say hi
classmethod:把類中的方法定義為類方法,使用classmethod裝飾的方法可以使用類或者類的實例對象來調(diào)用,并將該class對象隱式的作為第一個參數(shù)傳入
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
self.message = '111'
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
@classmethod
def speak(cls, message):
if not message:
message = 'hello'
cls.say(message)
human = Human()
human.speak('hi')
輸出同上例
property:把方法變成屬性
class Human(object): """docstring for Human""" def __init__(self, value): super(Human, self).__init__() self._age = value @property def age(self): return self._age human = Human(20) print human.age
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python Socket編程技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》及《Python入門與進階經(jīng)典教程》
希望本文所述對大家Python程序設(shè)計有所幫助。
相關(guān)文章
使用Python構(gòu)造hive insert語句說明
這篇文章主要介紹了使用Python構(gòu)造hive insert語句說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06
關(guān)于Python 常用獲取元素 Driver 總結(jié)
今天小編就為大家分享一篇關(guān)于Python 常用獲取元素 Driver 總結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
pyqt 實現(xiàn)在Widgets中顯示圖片和文字的方法
今天小編就為大家分享一篇pyqt 實現(xiàn)在Widgets中顯示圖片和文字的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06
Python調(diào)用IDM進行批量下載的實現(xiàn)
本文主要介紹了Python調(diào)用IDM進行批量下載的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
Centos部署django服務(wù)nginx+uwsgi的方法
這篇文章主要介紹了Centos部署django服務(wù)nginx+uwsgi的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01
Python Pandas兩個表格內(nèi)容模糊匹配的實現(xiàn)
模糊查詢大家應(yīng)該都不會陌生,下面這篇文章主要給大家介紹了關(guān)于Python Pandas兩個表格內(nèi)容模糊匹配的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2021-11-11
Python機器學(xué)習(xí)NLP自然語言處理基本操作電影影評分析
本文是Python機器學(xué)習(xí)NLP自然語言處理系列文章,帶大家開啟一段學(xué)習(xí)自然語言處理 (NLP) 的旅程。本篇文章主要學(xué)習(xí)NLP自然語言處理基本操電影影評分析2021-09-09

