python 函数装饰器(Function Decorators)

函数装饰器(Function Decorators)

python中函数装饰器的使用和Java中注解类似, 直接在函数定义的前一行加上装饰器即可. python除了函数装饰器还有类的装饰器.

使用及原理

@deco
def target():
    pass

这样target函数就被deco装饰了, 其中deco是一个接收一个函数为参数的函数.

decorators只是一种语法糖, 和以下代码是等价的

def target():
    pass
target = deco(target)

两段代码的结果是一样的, target指向的由deco返回的函数, 而不一定指向原来定义的target函数.

总结一下: 装饰器是一个接收一个函数作为参数(可能还有其他的参数)的函数, 它的返回值也是一个函数.

另外一个重要的是装饰器的函数在运行时马上被执行, 这个应该比较好理解. 也就是说当你运行时被装饰函数马上执行. 可以看看下面这个例子

def dec(func):
    print('the decorator function is excuting')
    return func
@dec
def target():
    print('excute target()')
    
def main():
    pass

if __name__ == '__main__':
    main()

执行结果

the decorator function is excuting

也就是说不管有没有调用target函数, target = dec(target)都会在一开始马上执行.

另外装饰器还可以嵌套使用, 比如:

@deco1
@deco2
def target():
    pass
#等价于
def target():
    pass
target = deco1(deco2(target))

实现

首先是一个打印日志的装饰器, 输出函数名称, 传入的参数, 返回值

import functools

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

@log
def add(a, b):
    return a + b

def main():
    res = add(4, 5)
    print(res)
    print(add.__name__)

if __name__ == '__main__':
    main()
    
'''
excute add(),  args: (4, 5) {} , res: 9
9
add
'''

注意到我这里使用了@functools.wraps(func), 它可以让wrapper.__name__ = func.__name__. 如果不加, 那么print(add.__name__)的结果将是wrapper.

另外一个例子, 记录函数运行时间

import functools, time

def clock(func):
    @functools.wraps(func)
    def clocks(*args, **kw):
        start = time.perf_counter()
        res = func(*args, **kw)
        elapsed = time.perf_counter() - start
        print('%s() excuted for %fs' % (func.__name__, elapsed))
        return res
    return clocks

@clock
def snooze(seconds):
    time.sleep(seconds)

def main():
    snooze(3)   

if __name__ == '__main__':
    main()
'''
snooze() excuted for 3.001641s
'''
    原文作者:前几
    原文地址: https://www.jianshu.com/p/8d1410760809
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞