python基础学习(八)-- 装饰器-d

作者:Shine 发布于:2018-07-20 18:00:06 浏览:863次 分类:PHP

python基础学习(八)-- 装饰器

import time
import functools


# 函数对象有一个__name__属性 可以拿到函数的名字
def now():
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), time.localtime()


f = now
print(now.__name__)
print(f.__name__)


# 但是现在我们要增强now()函数的功能 比如需要在函数调用前后打印日志 但又不想改变函数的定义 这种在代码运行期间动态添加功能的方式 称之为decorator(装饰器)
# 本质上decorator就是一个可以返回函数的高阶函数。所以我们要定义一个可以打印日志的decorator的,可以定义如下:


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

    return wrapper


# 上面的log是一个decorator 所以接受一个函数作为参数 并返回一个函数。我们需要借助py的@语法,将decorator置于函数的定义处
@log
def now_new():
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())


print(now_new())

# 在调用now_new函数前 会先打印一行日志 再调用now_new函数 相当于执行了now_nwe = log(now_new)

# 由于log是一个decorator 返回一个函数 所以原来的now_new函数还在 只不过是现在的 now_new指向了一个新的函数 所以调用now_new将执行一个新函数 即log函数中返回的wrapper函数
# wrapper函数的参数定义是(*args, **kw)所以可以接收任意参数 在wrapper函数内部 先print输出 再调用now_new函数

# 如果decorator本身需要传入参数,那就需要编写一个返回decorator的函数,比如要自定义log的文本

print('-------------------')


def new_log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__) + '--------\r\n')
            return func(*args, **kw)

        return wrapper

    return decorator


@new_log('execute')
def new_now():
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())


# print(new_now())

# 这个三层嵌套的效果相当于:
new_now = new_log('execute')(new_now)

print(new_now.__name__)


# 前面都没有问题 但是最后的new_now.__name__变了  因为返回的wrapper函数的__name__就是wrapper,我们需要吧原始的__name__等属性复制到wrapper函数中 否则一些依赖函数签名的函数代码就会执行出错

# 不需要编写wrapper.__name__ = func.__name__这样的代码 python内置的 functools.wraps就可以搞定  写法如下


def log(func):

    # 这里的wraps我猜也算是一个装饰器吧

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

    return wrapper


# practice:请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:


def log_time(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        start_time = time.time()
        res = func(*args, **kw)
        end_time = time.time()
        print('%s ran in %s seconds' % (func.__name__, (end_time - start_time) * 1000))
        return res

    return wrapper


@log_time
def test(x, y):
    time.sleep(1)
    return x + y


print(test(1, 2))


标签: python decorator
声明:文章内容由作者原创或整理,转载请标明出处!
暂留位置!--请勿随意修改