1、装饰器
在运行原来功能基础上,加上一些其它功能,比如权限的验证,比如日志的记录等。不修改原来的代码,进行功能的扩展。
2、decorator的功能:引入日志
函数执行时间统计
执行函数前预备处理
执行函数后清理功能
权限校验等场景
异常的处理
缓存
3、多个装饰器
一个函数被多个装饰器装饰的时候,按装饰器的顺序执行,最后执行函数。
#定义函数:完成包裹数据
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
#定义函数:完成包裹数据
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1()))
print(test2()))
print(test3()))
运行结果:
<b>hello world-1</b>
<i>hello world-2</i>
<b><i>hello world-3</i></b>
4、参数和返回值
为了通用性,装饰器的内部函数要有不定长参数和返回值。
from time import ctime, sleep
def timefun(func):
def wrappedfunc(*args, **kwargs):
print("%s called at %s"%(func.__name__, ctime()))
ret = func(*args, **kwargs)
return ret #可在适当的位置返回
return wrappedfunc
@timefun
def foo(a, b, c):
return a+b+c
print(foo(3,5,7))
sleep(2)
print(foo(2,4,9))
5、装饰器带参数,在原有装饰器的基础上,设置外部变量
#decorator2.py
from time import ctime, sleep
def timefun_arg(pre="hello"):
def timefun(func):
def wrappedfunc():
print("%s called at %s %s"%(func.__name__, ctime(), pre))
return func()
return wrappedfunc
return timefun
@timefun_arg("wangcai")
def foo():
print("I am foo")
@timefun_arg("python")
def too():
print("I am too")
foo()
sleep(2)
foo()
too()
sleep(2)
too()
可以理解为
foo()==timefun_arg("wangcai")(foo)()
6、类装饰器
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。
只要某个对象重写了 __call__() 方法,那么这个对象就是callable的。
lass Test():
def __call__(self):
print('call me!')
t = Test()
t() # call me
类装饰器demo
lass Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("---装饰器中的功能---")
self.__func()
#说明:
#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
# 并且会把test这个函数名当做参数传递到__init__方法中
# 即在__init__方法中的func变量指向了test函数体
#
#2. test函数相当于指向了用Test创建出来的实例对象
#
#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#
#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
@Test
def test():
print("----test---")
test()
showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"
运行结果如下:
---初始化---
func name is test
---装饰器中的功能---
----test---