装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。
基本知识请参考:https://www.runoob.com/w3cnote/python-func-decorators.html
有些重要的东西提一下:
1. 使用 @ 标识符将装饰器应用到函数
Python2.4以上支持使用标识符@将装饰器应用在函数上,只需要在函数的定义前加上@和装饰器的名称。:
@wrapper
def add(a, b):
return Coordinate(a.x + b.x, a.y + b.y)
多个decorator
@decorator_one
@decorator_two
def func():
pass
相当于:
func = decorator_one(decorator_two(func))
比如:带参数的decorator:
@decorator(arg1, arg2)
def func():
pass
相当于:
func = decorator(arg1,arg2)(func)
这意味着decorator(arg1, arg2)这个函数需要返回一个“真正的decorator”。
2.多个装饰器使用的调用顺序
def one(func):
print('----1----')
def two():
print('----2----')
func()
return two
def a(func):
print('----a----')
def b():
print('----b----')
func()
return b
@one
@a
def demo():
print('----3----')
demo()
执行结果:
/usr/bin/python2.7 /home/python/Desktop/tornadoProject/one.py
----a----
----1----
----2----
----b----
----3----
3.更通用的装饰器
*args and **kwarg的使用参考:https://blog.csdn.net/qq_19446965/article/details/104070046
有了这招新的技能,我们随随便便就可以写一个能够记录下传递给函数参数的装饰器了。例子:
def logger(func):
def inner(*args, **kwargs): #1
print "Arguments were: %s, %s" % (args, kwargs)
return func(*args, **kwargs) #2
return inner
请注意我们的函数inner,它能够接受任意数量和类型的参数并把它们传递给被包装的方法,这让我们能够用这个装饰器来装饰任何方法。
@logger
def foo1(x, y=1):
return x * y
@logger
def foo2():
return 2
foo1(5, 4)
#Arguments were: (5, 4), {}
#20
foo1(1)
#Arguments were: (1,), {}
#1
foo2()
#Arguments were: (), {}
#2
随便调用我们定义的哪个方法,相应的内容也会打印到输出窗口,和我们预期的一样。
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
这个3层嵌套的decorator用法如下:
@log('execute')
def now():
print '2013-12-25'
执行结果如下:
>>> now()
execute now():
2013-12-25
和两层嵌套的decorator相比,3层嵌套的效果是这样的:
now = log('execute')(now)
我们来剖析上面的语句,首先执行log('execute')
,返回的是decorator
函数,再调用返回的函数,参数是now
函数,返回值最终是wrapper
函数。
4.装饰器的副作用
函数也是对象,它有__name__
等属性,但你去看经过decorator装饰之后的函数,它们的__name__
已经从原来的'now'
变成了'wrapper'
:
>>> now.__name__
'wrapper'
因为返回的那个wrapper()
函数名字就是'wrapper'
,所以,需要把原始函数的__name__
等属性复制到wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写wrapper.__name__ = func.__name__
这样的代码,Python内置的functools.wraps
就是干这个事的,所以,一个完整的decorator的写法如下:
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
或者针对带参数的decorator:
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return wrapper
return decorator
在定义wrapper()
的前面加上@functools.wraps(func)
即可。
5. class式的 Decorator
首先,先得说一下,decorator的class方式,还是看个示例:
class myDecorator(object):
def __init__(self, fn):
print "inside myDecorator.__init__()"
self.fn = fn
def __call__(self):
self.fn()
print "inside myDecorator.__call__()"
@myDecorator
def aFunction():
print "inside aFunction()"
print "Finished decorating aFunction()"
aFunction()
# 输出:
# inside myDecorator.__init__()
# Finished decorating aFunction()
# inside aFunction()
# inside myDecorator.__call__()
1)一个是__init__(),这个方法是在我们给某个函数decorator时被调用,所以,需要有一个fn的参数,也就是被decorator的函数。
2)一个是__call__(),这个方法是在我们调用被decorator函数时被调用的。
上面输出可以看到整个程序的执行顺序。
这看上去要比“函数式”的方式更易读一些。
注意:如果decorator有参数的话,__init__() 成员就不能传入fn了,而fn是在__call__的时候传入的。
————————————————————————————
参考: