廖雪峰教程之学习笔记_webapp实战项目_自定义web框架

在廖雪峰教程的实战项目第五天的学习中,看到了这样的代码:

“要把一个函数映射为一个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

猜你喜欢

转载自blog.csdn.net/bird333/article/details/80638375