装饰器

装饰器就是返回函数的实际运用,装饰器接受一个原函数作为参数,返回值是一个现函数,调用装饰器就可以在原函数调用前后进行操作,而不改变原函数。

def now():
     print('2015-3-25')

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

log(now)()

以上述代码为例,now为原函数,log为装饰器,log接受函数func作为输入参数,返回wrapper函数作为返回值,而wrapper函数在func函数调用前打印日志,wrapper函数可以接受任意参数的调用,代表原始函数的参数可以是任意形式的。

最后的log(now)先返回wrapper,然后log(now)()就调用了wrapper(),而wrapper()首先打印了日志,然后返回了func(),而func()就是now()。

也可以使用@log对now重新定义,这样now就是一个装饰器

@log
def now():
    print('2015-3-25')

这样就相当于运行了now=log(now),因此直接运行now()就达到了上面的效果,但是now函数名指向的函数定义变化了。

如果装饰器本身需要输入参数,由于装饰器只能接受函数作为参数,所以又要在装饰器外面再套一层高阶函数,传入所需的参数,将装饰器函数作为最终的返回值返回  

如下所示:

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

调用时可以log('想要打印的日志')(now)(),也可以在原函数定义前加@log('想要打印的日志')

如果使用了装饰器重新定义函数,那么它的__name__等属性就变为了wrapper,因此需要在装饰器定义前加上@functools.wraps(func)

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

作业有个思考题解法很有意思

import functools
def log(args):
    if isinstance(args,str):
        def dec(func):
            @functools.wraps(func)
            def wrapper(*a,**kw):
                print('begin func',args)
                func(*a,**kw)
                print('end func')
            return wrapper
        return dec
    else:
        @functools.wraps(args)
        def wrapper(*a, **kw):
            print('begin func', args)
            args(*a, **kw)
            print('end func')
        return wrapper
@log('execute')
def f():
    print('I am here')
@log
def f():
    print('I am here')
f()

@log

def f():

  pass

等价于 f=log(f)

@log('execute')

def f():

  pass

等价于f=log('execute')(f)  

解法中根据log()括号中的参数类型是否为字符串来判断,如果参数为字符串,那么属于三层嵌套的装饰器,如果参数不是字符串,那么就将args作为被调用的函数名参数,即两层嵌套。  

课外阅读:

http://www.cnblogs.com/myd7349/p/how_to_use_wraps_of_functools.html 

posted on 2017-05-25 00:10  vonkimi  阅读(84)  评论(0编辑  收藏  举报

导航