什麼是裝飾器?
簡單來說,可以把裝飾器理解爲一個包裝函數
的函數,它一般將傳入的函數或者是類
做一定的處理,返回修改之後的對象。
所以我們能夠在不修改原函數
的基礎上,在執行原函數前後去執行別的代碼
,比較常用的場景有日誌插入,事務處理
等
我們知道,在python中函數也是被視爲對象的,可以作爲參數傳遞,那麼假如把計算機耗時操作 獨立爲一個單獨的函數,然後只要往裏頭傳入需要計算耗時的函數1 就可以不用往函數1中額外添加計算耗時的語句啦
def calc_spend_time(func,*args,**kargs):
start_time = datetime.datetime.now()
result = fun(*args,**kargs)
end_time = datetime.datetime.now()
print "result:",result,"used:",(end_time - start_time).microseconds
def calc_add(a,b):
return a + b
calc_spend_time(calc_add,1,1)
看起來也不錯,負責計算的函數不用更改代碼,只需調用的時作爲參數傳給計算時間差的函數。
但就是這,調用的時候形式變了,不再是clac(1,2),而是calc_spend_time(clac_add,1,2),萬一calc_add大規模被調用,那麼還得一處一處找,然後修改過來,還是很麻煩???
那麼可以在calc_spend_time()裏把傳入的calc_add()包裝一下,然後返回包裝後的新的函數,再將其賦值給clac_add,那麼calc_add()的效果就和calc_spend_time(calc(),*args,*kwargs)的效果一樣
import datetime
def calc_spend_time(func):
def new_func(a,b):
start_time = datetime.datetime.now()
result = fumc(a,b)
end_time = datetime.datetime.now()
print "result:",result,"used:",(end_time - start_time).microseconds
return new_func
def calc_add(a,b):
return a + b
calc_add = calc_spend_time(calc_add)
calc_add(1,2)
語法糖:
上面的列子就是裝飾器的概念,包含函數的函數<函數內部定義一個函數,這個函數需要調用某一個函數>
,上面的例子還可以更簡潔
import datetime
def calc_spend_time(func):
def new_func(a,b):
start_time = datetime.datetime.now()
result = func(a,b)
end_time = datetime.datetime.now()
print "result",result,"used:",(end_time - start_time).microseconds,"us"
return new_func
@calc_spend_time
def calc_add(a,b):
return a+b
calc_add(1,2)
分析
@calc_spend_time就是語法糖,它的本質就是:calc_add = calc_spend_time(calc_add)
無參數的函數裝飾器
import datetime
def calc_spend_time(func):
def new_func(*args,**kargs):
start_time = datetime.datetime.now()
result = func(*args,**kargs)
end_time = datetime.datetime.now()
print "result:",result,"used:",(end_time - start_time).microseconds,"us"
result 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:把所有的參數按出現的順序打包成tuple
**kargs:把所有的key=value形式的參數打包成一個dict
帶參數的函數裝飾器
假如我們需要知道函數的一些額外的信息,假如函數作者,可以通過給裝飾器函數增加參數來實現
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_time = datetime.datetime.now()
print author,"result:",result,"used:",(end_time - start_time).microseconds,"us"
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
# 0. calc_spend_time('author_1')
# 1. calc_add=first_func(calc_add)
# 2. cal_add(1,2) =>> new_func(1,2)
calc_add(a=1,b=2)
calc_diff(1,2)
python內置裝飾器
python內置的裝飾器有三個:
staticmethod
classmethod
property
staticmethod
把類中的方法定義爲靜態方法,使用staticmethod裝飾的方法可以使用類或者類的實例對象來調用,不需要傳入self
class Human(object):
"docstring for Human"
def __int__(self):
super(Human,self).__int__()
@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
classmmethod
把類中的方法定義爲類的方法,
使用classmethod裝飾的方法可以使用類的或者類的實例對象來調用,
並將該class對象隱式的作爲第一個參數傳入
class Human(object):
"""docstring for Human"""
def __int__(self):
super(Human,self).__init__()
self.message = '111'
def say(message):
if not message:
message = "hlleo"
print "I say %s" %message
@classmethod
def speak(cls,message):
if not message:
message = 'hello'
cls.say(message)
human = Human()
human.speak('hi')
輸出:
I say hello
I say hi
property
把方法變成屬性
class Human(object):
def __init__(self,value):
super(Human,self).__init__()
self.arg = value
@property
def age(self):
return self._age
human = Human(20)
print human.age