簡單的說,@裝飾器就是用來提供調用的,
def funA(arg):
print 'A'
a=arg()
@funA
def funB():
print 'B'
輸出結果爲
此處的@相當於funA(funB())。
裝飾器背後的主要動機源自python面向對象編程,裝飾器是在函數調用之上的修飾,這些修飾僅是當聲明一個函數或者方法的時候,纔會應用的額外調用。
裝飾器的語法以@開頭,接着是裝飾器韓式的名字和可選的參數。緊跟着裝飾器聲明的是被修飾的函數,和修飾函數的可選參數。
class MyClass(obj):
@staticmethod
def staticFoo():
...
利用staticmethod內建函數來將這個函數“轉化”爲靜態方法,利用裝飾器會很簡潔。
@g
@f
def foo():
...
..與foo=g(f(foo))相同
有參數和無參數的裝飾器
@deco
def foo():
pass
…非常直接
foo=deco(foo)
有參數的裝飾器
@decomaker(deco_args)
deffoo():
pass
需要自己返回以函數作爲參數的裝飾器,換句話說,decomaker()用deco_args做了些事情並返回函數對象,而該函數正是以foo作爲其參數的裝飾器,相當於:
foo=decomaker(deco_args)(foo)
多個裝飾器的例子,其中一個裝飾器帶有一個參數:
@deco1(deco_args)
@deco2
def func():pass
等價於:
func=deco1(deco_args) (deco2(func))
什麼是裝飾器
現在我們知道裝飾器實際上就是一個函數,我們也知道他們接受函數對象,但他們是怎麼處理那些函數?當你包裝一個函數的時候,你最終會調用它,最棒的是我們能夠在包裝的環境下在合適的時機調用它,我們在執行函數之前,可以運行那些預備代碼,如 post-morren分析,也可以在執行代碼之後做個清理工作,所以當你看見一個裝飾器函數的時候,很可能在裏面找到這樣一些代碼,它定義了某個函數並在定義內的某處嵌入了對目標函數的調用或者至少一些引用。從本質上看,這些特徵引入了java開發者稱之爲AOP的概念,可以考慮在裝飾器中置入通用功能的代碼來降低程序複雜度。
可以用裝飾器來:
- 引入日誌
- 增加計時邏輯來檢測性能
- 給函數加入事物能力。
----------------------------------------------------------------------------------------------------------------------------------
1. @prototype修飾符的用法
class Person(object):
def __init__(self):
self.__x = None
def setx(self, value):
self.__x = value
def getx(self):
return self.__x
def delx(self):
del self.__x
x = property(getx, setx, delx)
p = Person()
p.x = 123 # 自動調用 setx 方法
print p.x # 自動調用 getx 方法
del p.x # 自動調用 delx 方法
另外一種用法:
class Person(object):
def __init__(self):
self.__x = None
@prototype
def x(self):
return self.__x
@x.setter
def x(self, value):
self.__x = value
@x.deleter
def x(self):
del self.__x
p = Person()
p.x = 123 # 自動調用 setx 方法
print p.x # 自動調用 getx 方法
del p.x # 自動調用 delx 方法
2. staticmethod修飾符
被staticmethod修飾符的表示這是一個類的靜態方法,可以被類直接調用
class Person(object):
@staticmethod
def hello():
print 'hello world!!!'
if __name__ == '__main__':
Pserson.hello()
3. 裝飾器。
實例:
def now()
print '2016-05-11'
now()
如果我想在now執行前執行另外一個方法,而不修改now方法呢?那麼就用到了裝飾器
def log(func):
# func 參數傳遞的值就是 now方法
def wrap(*args, **kw):
# *args, **kw 方法接收任何形式的參數
print '2016-05-10'
return func(*args, **kw) # 執行now方法
return wrap
@log
def now():
print '2016-05-11'
now() # 相當於執行 now = log(now),可以看到 func 就是 now的值,用裝飾方法覆蓋now
問題來了,我想傳遞參數呢?
def log(text):
def decorator(func):
def wrap(*args, **kw):
print text
return func(*args, **kw)
return wrap
return decorator
@log('2016-05-10')
def now():
print '2016-05-11'
now() # 相當於執行 now = log('2016-05-10')(now)
那麼裝飾器就完了麼?如果是當前的功能,那麼就可以了,但是有的地方如果使用了函數簽名(屬性),就要出問題了。
print now.__name__
#result: wrap
函數名字怎麼變成wrap了呢?如果某些代碼用到使用函數簽名(屬性)就要出問題了。
python的functools模塊提供了修改函數屬性的方法wraps
from functools import wraps
def log(text):
def decorator(func):
@wraps(func)
def wrap(*args, **kw):
print text
return func(*args, **kw)
return wrap
return decorator
@log('2016-05-10')
def now():
print '2016-05-11'
now()
print now.__name__ # now