在廖雪峰教程的实战项目第五天的学习中,看到了这样的代码:
“要把一个函数映射为一个URL处理函数,我们先定义@get()
:”
def get(path):
'''
Define decorator @get('/path')
'''
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
return func(*args, **kw)
wrapper.__method__ = 'GET'
wrapper.__route__ = path
return wrapper
return decorator
涉及到自定义装饰器的内容。廖雪峰在前面的课程中讲过,但是没有理解。在此,再复习深入一遍。
***************************************************************************************************************************
在python中,函数也是一个对象,而且可以赋值给变量。(类似于c++中的引用吧,对python来说,函数名就是一个指向一个函数名字,这个名字也可以传给别的函数,别的函数也知道了这个名字,也可以使用)
“装饰器”Decorator的定义:在函数代码运行期间动态增加功能的方法。
比如:
有一个now()函数
def now():
print('2015-09-06')
要想在now()运行期间添加功能,我们想到了高阶函数(把函数当变量传递给高阶函数函数),实际上装饰器的本质就是高阶函数。
1 自定义装饰器
下面编写一个在函数运行前,打印一行字的装饰器(Decorator).
def log(func):
def wrapper(*args,**kw):
print('call %s(): func.__name__)
return func(*args,**kw)
return wrapper
func函数传入log高阶函数,在log内定义了wrapper函数(wrapper打印了一行字,又返回了func函数),又把wrapper函数返回。所以,log函数就是接受func函数,打印一行字,再返回同名的func函数。
2 使用装饰器
log这个装饰器,接受函数作为参数。把@log置于函数的定义处。
@log
def now():
print('2015-09-06'
now = log(now)。看出来,新now把旧的now函数覆盖了
再执行now()函数时,执行的是经过log(now)处理过的新now函数。
3 装饰器本身还有其他参数
如果想使用这样的装饰器@log(text),text是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
这样的装饰器应当这样使用:
now =
now = log('execute')(now)
剖析:log('execute')得到的是decorator(func),所以
log('execute')(now)
相当于decorator(now)。decorator(now)又返回wrapper函数,wrapper函数打印了一行字,又返回了func()函数。
完成了装饰器(带参数)的功能。
4 functool.wraps
经过装饰器改造的函数的__name__属性值会变化,比如@log实际返回的是wrapper函数,因此__name__会变成'wrapper',但是这并不是我们所想的。functool.wraps就是帮助我们改名字的。
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