前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python functools.wraps装饰器模块

python functools.wraps装饰器模块

作者头像
周小董
发布2019-03-25 15:58:21
8330
发布2019-03-25 15:58:21
举报
文章被收录于专栏:python前行者python前行者
代码语言:javascript
复制
# -*-coding=utf-8 -*-
#实现一个函数执行后计算执行时间的功能

__author__ = 'piay'
import time, functools


def foo():
    '''
    定义一个普通函数
    :return:
    '''
    print 'this is foo'


foo()

'''
这里如果我们需要查看函数执行时间,修改为:
'''


def foo1():
    start_time = time.clock()
    print 'this is foo1'
    end_time = time.clock()
    print '执行时间为:', end_time - start_time


foo1()

'''
如果我们其他的函数也需要执行时间,或者这个函数不需要执行时间,那么我们就需要复制到其他的函数中去
这是一种最差的方法
'''


def foo3():
    print 'this is foo3'


def timeit(func):
    '''
    我们可以考虑重新定义一个函数timeit,将foo的引用传递给他,
    然后在timeit中调用foo并进行计时,这样,我们就达到了不改动foo定义的目的
    :param func: 传入的函数
    :return:
    '''
    start_time = time.clock()
    func()
    end_time = time.clock()
    print 'used:', end_time - start_time


timeit(foo3)
'''
这样写修改调用部分的代码。原本我们是这样调用的:foo3(),现在变成timeit(foo),这样的话,如果foo在N处都被调用了,
你就不得不去修改这N处的代码。或者更极端的,考虑其中某处调用的代码无法修改这个情况,比如:这个函数是你交给别人使用的。
'''

'''
想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用foo()需要产生调用timeit(foo)的效果。我们可以想到将timeit赋值给foo,
但是timeit似乎带有一个参数……想办法把参数统一吧!如果timeit(foo)不是直接产生调用效果,
而是返回一个与foo参数列表一致的函数的话……就很好办了,将timeit(foo)的返回值赋值给foo,然后,调用foo()的代码完全不用修改!
'''


def foo4():
    print 'this is foo4'


# 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法
def timeit4(func):
    # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
    def wrapper():
        start_time = time.clock()
        func()
        end_time = time.clock()
        print 'used:', end_time - start_time

    # 将包装后的函数返回
    return wrapper


foo_1 = timeit(foo4)
'''
上面的代码就类似装饰器了,可以修改为如下:
'''


@timeit4  # 定义上加上这一行与另外写foo = timeit(foo)完全等价
def foo5():
    print 'this is foo5'
foo5()


'''
-----------------------------------------------
使用functools.wraps(func)装饰器实现功能
'''
def timeit_3_for_wraps(func):
    @functools.wraps(func)
    def wrapper():
        start=time.clock()
        func()
        end=time.clock()
        print 'used:',end-start
    return wrapper

@timeit_3_for_wraps
def foo6():
    print 'this is foo6'
foo6()

这里实现一个完整的判断是否带参数的装饰器:

代码语言:javascript
复制
# -*-coding=utf-8 -*-
__author__ = 'piay'
import functools, time
'''
一个函数执行前打印开始执行,执行完后打印执行完成,记录执行时间
'''

def log(text):
    if callable(text):  # 参数如果是函数,说明装饰器不带参传过来,text是一个函数
        @functools.wraps(text)
        def wrapper(*args, **kwargs):
            start = time.clock()
            print '这是不带参数的装饰器,开始执行'
            f = text(*args, **kwargs)  #执行本身的函数 text()
            end = time.clock()
            print "结束执行:", end - start
            return f  # 返还原函数
        return wrapper

    elif not callable(text):  # text是参数,不是函数
        def decarator(func):
            @functools.wraps(func)
            def warpper(*args, **kwargs):
                start = time.clock()
                print '这是不带参数的装饰器,开始执行,参数为:'+text
                f = func(*args, **kwargs)
                end=time.clock()
                print "结束执行:",end-start
                return f  #返还原函数
            return warpper
        return decarator
    else:
        print '请检查是否正确'


@log
def add1(x,y):
    print x+y

@log('222')
def add2(x,y):
    print  x+y

add1(1,2)
add2(2,3)

执行结果:

D:\Python27\python.exe D:/Python/functools_study/完整的装饰器.py 这是不带参数的装饰器,开始执行 3 结束执行: 5.08444509009e-05 这是不带参数的装饰器,开始执行,参数为:222 5 结束执行: 2.49333364995e-05

Process finished with exit code 0

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年06月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档