python中的装饰器
作者:向前的步伐 / 发表: 2019年6月26日 21:36 / 更新: 2019年6月26日 22:19 / python / 阅读量:677
python中的装饰器本质上是一个函数,它可以让其他函数在不做任何改变的情况下增加额外的功能,装饰器返回的是一个函数对象。它经常用于插入日志、权限检验、登陆验证等场景。
在理解装饰器之前,我们想理解下闭包的概念。
闭包:在计算机科学中,闭包,又称为词法闭包,或者函数闭包,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
简单的看个例子:
def func():
data = 'the data value'
def getdata():
print(data)
return getdata
# 这里获取的就是一个闭包
data_value = func()
# 这里打印‘the data value’
data_value()
这里的data就是一个局部变量,在func函数执行之后,该变量就不存在了。但是里面的嵌套函数使用了这个变量,将这个变量封闭在嵌套的函数中,这样就形成了一个闭包。
装饰器的使用,也和这个闭包类似,可以看看平时封装的一个简单的插入日志的装饰器:
import functools
def log(func):
@functools.wraps(func):
def wrapper(*args, **kwargs)
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
return func(*args, **kwargs)
return wrapper
@log
def test(msg):
print('test function')
print('msg: ', msg)
test('hello')
使用装饰器时,使用了@语法,其实本质上来讲,它也就是一个函数,参数时函数对象,返回也是函数对象,和下面这种方式没有任何区别:
import functools
def log(func):
@functools.wraps(func):
def wrapper(*args, **kwargs)
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
return func(*args, **kwargs)
return wrapper
def test(msg):
print('test function')
print('msg: ', msg)
wrapper = log(test)
wrapper('hello')
当然这个装饰器里面要关注的是@functools.wraps(func)语句,这个python自带的一个装饰器,主要作用就是将原函数的元信息拷贝到装饰器里的func对象,这样可以获取到被调用的函数的name、参数列表等等。
装饰器也是可以带参数,代码如下:
import functools
def record_by_name(name):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs)
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
print('record by %s.' % name)
return func(*args, **kwargs)
return wrapper
return decorator
@record_by_name('reda')
def test(msg):
print('test function')
print('msg: ', msg)
test('hello')
这个带参数的装饰器,看上去挺复杂的,但是在理解了普通的装饰器的使用之后,其实很好理解。只要把最外层的record_by_name函数拿走,此时里面的decorator就和之前的log装饰器一模一样了。而record_by_name('reda')返回的就是decorator函数对象,也就是之前的log函数对象,所以@record_by_name('reda')等同于@log,这样理解起来就是和之前的装饰器没有啥区别了,就是多传递了一个参数值。
装饰器在python中使用的还是比较多的,在以后使用过程中会有更大的体会。