裝飾器的主要功能:在不改變函數調用方式的基礎上在函數的前、後添加功能 ,相似C#的AOP編程。添加功能的這部分就在裝飾器中,典型的格式以下:編程
def timer(func): def inner(*args,**kwargs): '''執行函數以前要作的''' re = func(*args,**kwargs) '''執行函數以後要作的''' return re return inner from functools import wraps def deco(func): @wraps(func) #加在最內層函數正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
好比咱們給fun增長一個記時的裝飾器,還要考慮到函數的參數調用app
import time def timer(f): # 裝飾器函數 def inner(*argc, **kwargc): start = time.time() ret = f(*argc, **kwargc) # 被裝飾的函數 end = time.time() print(end - start) return ret return inner @timer # 語法糖 @裝飾器函數名,至關於調用func=timmer(func) def func(name): # 緊挨着被裝飾函數 time.sleep(0.01) print("hello:%s" % name) return "first time:"+name
運行結果以下:函數
hello:gavin
0.010966062545776367
first time:gavinspa
兩個有用的宏:fun的__name__查看字符串格式的函數名,__doc__查看函數的註釋code
from functools import wraps def wrapper(func): #func = holiday @wraps(func) def inner(*args,**kwargs): print('在被裝飾的函數執行以前作的事') ret = func(*args, **kwargs) print('在被裝飾的函數執行以後作的事') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): '''這是一個放假通知''' print('全體放假%s天'%day) return '好開心' print(holiday.__name__) print(holiday.__doc__) ret = holiday(3) #inner print(ret)
運行結果:blog
holiday
這是一個放假通知
在被裝飾的函數執行以前作的事
全體放假3天
在被裝飾的函數執行以後作的事
好開心
帶參數的裝飾器:假如你有成千上萬個函數使用了一個裝飾器,如今你想把這些裝飾器都取消掉,你要怎麼作?一個一個的取消掉?utf-8
import time FLAGE = False def timmer_out(flag): def timmer(func): def inner(*args, **kwargs): if flag: start = time.time() ret = func(*args, **kwargs) end = time.time() print(end-start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer # timmer = timmer_out(FLAGE) @timmer_out(FLAGE) #wahaha = timmer(wahaha) def wahaha(): time.sleep(0.1) print('wahahahahahaha') @timmer_out(True) def erguotou(): time.sleep(0.1) print('erguotoutoutou') wahaha() erguotou()
運行結果:字符串
wahahahahahaha
erguotoutoutou
0.10001111030578613string
多個裝飾器裝飾同一個函數:io
def wrapper1(func): def inner1(): print('wrapper1 ,before func') ret = func() print('wrapper1 ,after func') return ret return inner1 def wrapper2(func): def inner2(): print('wrapper2 ,before func') ret = func() print('wrapper2 ,after func') return ret return inner2 def wrapper3(func): def inner3(): print('wrapper3 ,before func') ret = func() print('wrapper3 ,after func') return ret return inner3 @wrapper3 @wrapper2 @wrapper1 def f(): print('in f') return '哈哈哈' print(f())
運行結果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈
functools的wrap:Python裝飾器(decorator)在實現的時候,被裝飾後的函數其實已是另一個函數了(函數名等函數屬性會發生改變),爲了避免影響,Python的functools包中提供了一個叫wraps的decorator來消除這樣的反作用。寫一個decorator的時候,最好在實現以前加上functools的wrap,它能保留原有函數的名稱和docstring。
不加wraps:
# coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
運行結果是:
wrapper decorator
返回的值裝飾器的名稱和註釋;加wraps:
# coding=utf-8 # -*- coding=utf-8 -*- from functools import wraps def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): '''decorator''' print('Calling decorated function...') return func(*args, **kwargs) return wrapper @my_decorator def example(): """Docstring""" print('Called example function') print(example.__name__, example.__doc__)
運行結果:
example Docstring
是源函數的定義和註釋