装饰器的作用无疑是在函数执行的前后添加额外的内容,以满足我们需要的需求,例如日志处理,性能测试,事物处理等。
1:最简单的实现前后添加类容的需求:
#!/usr/bin/python
#-*-coding:utf-8-*-
#deco1.py
def deco(func):
print 'before'
func()
print 'after'
def myfunc():
print 'myfunc'
myfunc=deco(myfunc)
before
myfunc
after
#!/usr/bin/python
#-*-coding:utf-8-*-
#deco2.py
def deco(func):
def wrapper():
print 'before'
func()
print 'after'
return wrapper
def myfunc():
print 'myfunc'
myfunc=deco(myfunc)
myfunc()
before
myfunc
after
wrapper
#!/usr/bin/python
#-*-coding:utf-8-*-
#deco3.py
def deco(func):
def wrapper():
print 'before'
func()
print 'after'
return wrapper
@deco
def myfunc():
print 'myfunc'
myfunc()
print myfunc.__name__
before
myfunc
after
wrapper
无疑可以看出来 @deco 相当于执行了命令 myfunc=deco(myfunc) 这一个命令,同时它也就只是这样而已
4:带有参数的高阶装饰器:
#!/usr/bin/python
#-*-coding:utf-8-*-
#deco4.py
def outer(text):
def deco(func):
def wrapper(*args,**kw):
print 'before'
print text
func(*args,**kw)
print 'after'
return wrapper
return deco
@outer('hello outer')
def myfunc(name):
print 'myfunc',name
myfunc('licheng')
print myfunc.__name__
before
hello outer
myfunc licheng
after
wrapper
无疑语法糖加上参数也只是在外围包上了一层函数和返回值而已。 @outer('hello outer')相当于 myfunc=outer('hello outer')(myfunc)
5:解决函数名的问题
上述装饰器基本已经可以说完整了 但是依旧存在一个问题,那就是我们可以看到经过装饰后,myfunc的函数名变成了wrapper.显然这对于一些依赖于函数名的反射机制会发生异常错误等。因此我们需要将 myfunc.__name__ =myfunc 实现
而这只需要一句话 @functools.wraps(func)就可以实现。
#!/usr/bin/python
#-*-coding:utf-8-*-
#deco4.py
import functools
def outer(text):
def deco(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print 'before'
print text
func(*args,**kw)
print 'after'
return wrapper
return deco
@outer('hello outer')
def myfunc(name):
print 'myfunc',name
myfunc('licheng')
print myfunc.__name__
before
hello outer
myfunc licheng
after
myfunc
这个装饰器 @functools.wraps(func) 是functools的一个特殊的装饰器,相当于 wrapper=functools.wraps(func)(wrapper)