python函数装饰器参数统计调用时间和次数

1 python函数装饰器参数统计调用时间和次数

python在函数装饰器外层定义一个函数生成封闭作用域来保存装饰器入参,供装饰器使用。

1.1 装饰器统计调用时间和次数

描述

通过类的可调用实例装饰器来统计函数每次调用时间和总调用时间,以及调用次数。

(1) time.perf_counter()获取当前时间,单位秒;

(2) 调用函数func前和后的时间差,为func的执行时间usetime;

(3) 将每次的执行时间usetime累加,获得总时间alltime;

(4) 每调用一次func,calls计增一次获得总次数;

(5) 比较列表解析和map内置函数生成列表的调用时间;

(6) map在py2返回列表,在py3返回迭代器,需用list转为列表;

示例

python 复制代码
>>> import time,sys
>>> class TimeCount:
    def __init__(self,func):
        self.func=func
        self.alltime=0
        self.calls=0
    def __call__(self,*args,**kargs):
        begin=time.perf_counter()
        res=self.func(*args,**kargs)
        usetime=time.perf_counter()-begin
        self.alltime+=usetime
        self.calls+=1
        callstr=' 调用 {0[0]} {0[1]} 次 '
        calltpl=self.func.__name__,self.calls
        timestr='{0[0]}:usetime={0[1]:.6f},alltime={0[2]:.6f}'
        timetpl=self.func.__name__,usetime,self.alltime
        resstr='res[0]={0[0]},res[-1]={0[1]},len(res)={0[2]}'
        restpl=res[0],res[-1],len(res)
        print(callstr.format(calltpl).center(50,'-'))
        print(timestr.format(timetpl))
        print(resstr.format(restpl),'\n')

>>> @TimeCount
def listcomp(N):
    return [x*2 for x in range(N)]

>>> if sys.version_info[0]==2:
    @TimeCount
    def mapcall(N):
        return map((lambda x:x*2),range(N))
else:
    @TimeCount
    def mapcall(N):
        # py3的map返回迭代器需用list转换
        # 否则统计的时间与listcomp不一致
        return list(map((lambda x:x*2),range(N)))

>>> xtpl=5,50000,500000,1000000
>>> tuple(map(listcomp,xtpl))
---------------- 调用 listcomp 1 次 -----------------
listcomp:usetime=0.000005,alltime=0.000005
res[0]=0,res[-1]=8,len(res)=5 

---------------- 调用 listcomp 2 次 -----------------
listcomp:usetime=0.002395,alltime=0.002400
res[0]=0,res[-1]=99998,len(res)=50000 

---------------- 调用 listcomp 3 次 -----------------
listcomp:usetime=0.026660,alltime=0.029060
res[0]=0,res[-1]=999998,len(res)=500000 

---------------- 调用 listcomp 4 次 -----------------
listcomp:usetime=0.053023,alltime=0.082084
res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> tuple(map(mapcall,xtpl))
----------------- 调用 mapcall 1 次 -----------------
mapcall:usetime=0.000005,alltime=0.000005
res[0]=0,res[-1]=8,len(res)=5 

----------------- 调用 mapcall 2 次 -----------------
mapcall:usetime=0.003963,alltime=0.003968
res[0]=0,res[-1]=99998,len(res)=50000 

----------------- 调用 mapcall 3 次 -----------------
mapcall:usetime=0.041263,alltime=0.045231
res[0]=0,res[-1]=999998,len(res)=500000 

----------------- 调用 mapcall 4 次 -----------------
mapcall:usetime=0.083637,alltime=0.128868
res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> '{:.6f}'.format(mapcall.alltime)
'0.128868'
>>> '{:.6f}'.format(listcomp.alltime)
'0.082084'
>>> '{:.6f}'.format(mapcall.alltime/listcomp.alltime)
'1.569957'

1.2 嵌套函数统计电影时间和次数

描述

通过嵌套函数来统计函数每次调用时间和总调用时间,以及调用次数。

(1) time.perf_counter()获取当前时间,单位秒;

(2) 调用函数func前和后的时间差,为func的执行时间usetime;

(3) 将每次的执行时间usetime累加,获得总时间alltime;

(4) 每调用一次func,calls计增一次获得总次数;

(5) 比较列表解析和map内置函数生成列表的调用时间;

(6) map在py2返回列表,在py3返回迭代器,需用list转为列表;

(7) 将alltime和calls赋值给func进行返回,供后续获取;

(8) 通过nonlocal修改嵌套作用域的变量alltime和calls;

示例

python 复制代码
>>> import time,sys
>>> def timecount_func(func):
    alltime=0
    calls=0
    def tcf_wrapper(*pargs,**kargs):
        begin = time.perf_counter()
        res=func(*pargs,**kargs)
        usetime = time.perf_counter() - begin
        nonlocal alltime
        nonlocal calls
        alltime+=usetime
        calls+=1
        timestr='{0[0]}:usetime={0[1]:.6f},alltime={0[2]:.6f}'
        timetpl=func.__name__,usetime,alltime
        callstr=' 调用 {0[0]} {0[1]} 次 '
        calltpl=func.__name__,calls
        resstr='res[0]={0[0]},res[-1]={0[1]},len(res)={0[2]}'
        restpl=res[0],res[-1],len(res)
        print(callstr.format(calltpl).center(50,'-'))
        print(timestr.format(timetpl))
        print(resstr.format(restpl),'\n')
        func.alltime=alltime
        func.calls=calls
    return tcf_wrapper

>>> def listcomp(N):
    return [x*2 for x in range(N)]

>>> if sys.version_info[0]==2:
    def mapcall(N):
        return map((lambda x:x*2),range(N))
else:
    def mapcall(N):
        return list(map((lambda x:x*2),range(N)))
        
>>> xtpl=5,50000,500000,1000000
>>> tuple(map(timecount_func(listcomp),xtpl))
---------------- 调用 listcomp 1 次 -----------------
listcomp:usetime=0.000005,alltime=0.000005
res[0]=0,res[-1]=8,len(res)=5 

---------------- 调用 listcomp 2 次 -----------------
listcomp:usetime=0.002478,alltime=0.002482
res[0]=0,res[-1]=99998,len(res)=50000 

---------------- 调用 listcomp 3 次 -----------------
listcomp:usetime=0.031966,alltime=0.034448
res[0]=0,res[-1]=999998,len(res)=500000 

---------------- 调用 listcomp 4 次 -----------------
listcomp:usetime=0.068800,alltime=0.103248
res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> tuple(map(timecount_func(mapcall),xtpl))
----------------- 调用 mapcall 1 次 -----------------
mapcall:usetime=0.000006,alltime=0.000006
res[0]=0,res[-1]=8,len(res)=5 

----------------- 调用 mapcall 2 次 -----------------
mapcall:usetime=0.004435,alltime=0.004441
res[0]=0,res[-1]=99998,len(res)=50000 

----------------- 调用 mapcall 3 次 -----------------
mapcall:usetime=0.041257,alltime=0.045698
res[0]=0,res[-1]=999998,len(res)=500000 

----------------- 调用 mapcall 4 次 -----------------
mapcall:usetime=0.082711,alltime=0.128409
res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> '{:.6f}'.format(mapcall.alltime)
'0.128409'
>>> '{:.6f}'.format(listcomp.alltime)
'0.103248'
>>> '{:.6f}'.format(mapcall.alltime/listcomp.alltime)
'1.243693'

1.3 函数装饰器参数

通过装饰器参数指定配置选项。在装饰的时候传入一个标签和一个跟踪控制标志。

提供一个输出标签,以及打开或关闭跟踪消息,

用法

python 复制代码
def close_scope_func(label='',trace=True):
    def decorator(func):
        def onCall(*args):
            pass
            func(*args)
            pass
    return decorator
    
@close_scope_func('梯阅线条')
def test_func(x):
    pass

test_func('tyxt')

描述

装饰器参数需在外层添加一个函数生成一个封闭作用域用来保存参数,供装饰器使用。

(1) 在装饰器外层定义一个函数,并且指定装饰器需要的入参;

(2) 外层函数需返回一个可调用的装饰器,给到被装饰函数;

(3) 装饰函数时,传入对应入参即可;

示例

python 复制代码
>>> import time,sys
>>> def timecount_ctr(label='',trace=True):
    class TimeCount:
        def __init__(self,func):
            self.func=func
            self.alltime=0
            self.calls=0
        def __call__(self,*args,**kargs):
            begin=time.perf_counter()
            res=self.func(*args,**kargs)
            usetime=time.perf_counter()-begin
            self.alltime+=usetime
            self.calls+=1
            if trace:
                callstr=' 调用 {0[0]} {0[1]} 次 '
                callval=self.func.__name__,self.calls
                timestr='{0[0]}:usetime={0[1]:.6f},alltime={0[2]:.6f}'
                timeval=self.func.__name__,usetime,self.alltime
                resstr='res[0]={0[0]},res[-1]={0[1]},len(res)={0[2]}'
                resval=res[0],res[-1],len(res)
                print(label,callstr.format(callval).center(50,'-'))
                print(label,timestr.format(timeval))
                print(label,resstr.format(resval),'\n')
    return TimeCount

>>> @timecount_ctr('[listcomp]==>')
def listcomp(N):
    return [x*2 for x in range(N)]

>>> if sys.version_info[0]==2:
    @timecount_ctr('[mapcall]==>')
    def mapcall(N):
        return map((lambda x:x*2),range(N))
else:
    @timecount_ctr('[mapcall]==>')
    def mapcall(N):
        # py3的map返回迭代器需用list转换
        # 否则统计的时间与listcomp不一致
        return list(map((lambda x:x*2),range(N)))

>>> xtpl=5,50000,500000,1000000
>>> tuple(map(listcomp,xtpl))
[listcomp]==> ---------------- 调用 listcomp 1 次 -----------------
[listcomp]==> listcomp:usetime=0.000005,alltime=0.000005
[listcomp]==> res[0]=0,res[-1]=8,len(res)=5 

[listcomp]==> ---------------- 调用 listcomp 2 次 -----------------
[listcomp]==> listcomp:usetime=0.002641,alltime=0.002646
[listcomp]==> res[0]=0,res[-1]=99998,len(res)=50000 

[listcomp]==> ---------------- 调用 listcomp 3 次 -----------------
[listcomp]==> listcomp:usetime=0.027689,alltime=0.030335
[listcomp]==> res[0]=0,res[-1]=999998,len(res)=500000 

[listcomp]==> ---------------- 调用 listcomp 4 次 -----------------
[listcomp]==> listcomp:usetime=0.052438,alltime=0.082773
[listcomp]==> res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> tuple(map(mapcall,xtpl))
[mapcall]==> ----------------- 调用 mapcall 1 次 -----------------
[mapcall]==> mapcall:usetime=0.000004,alltime=0.000004
[mapcall]==> res[0]=0,res[-1]=8,len(res)=5 

[mapcall]==> ----------------- 调用 mapcall 2 次 -----------------
[mapcall]==> mapcall:usetime=0.003975,alltime=0.003979
[mapcall]==> res[0]=0,res[-1]=99998,len(res)=50000 

[mapcall]==> ----------------- 调用 mapcall 3 次 -----------------
[mapcall]==> mapcall:usetime=0.040665,alltime=0.044644
[mapcall]==> res[0]=0,res[-1]=999998,len(res)=500000 

[mapcall]==> ----------------- 调用 mapcall 4 次 -----------------
[mapcall]==> mapcall:usetime=0.098298,alltime=0.142942
[mapcall]==> res[0]=0,res[-1]=1999998,len(res)=1000000 

(None, None, None, None)
>>> '{:.6f}'.format(mapcall.alltime)
'0.142942'
>>> '{:.6f}'.format(listcomp.alltime)
'0.082773'
>>> '{:.6f}'.format(mapcall.alltime/listcomp.alltime)
'1.726914'
相关推荐
墨理学AI3 分钟前
一文学会一点python数据分析-小白原地进阶(mysql 安装 - mysql - python 数据分析 - 学习阶段梳理)
python·mysql·数据分析
数研小生10 分钟前
亚马逊商品列表API详解
前端·数据库·python·pandas
独好紫罗兰10 分钟前
对python的再认识-基于数据结构进行-a005-元组-CRUD
开发语言·数据结构·python
jianghua00122 分钟前
Python中的简单爬虫
爬虫·python·信息可视化
喵手32 分钟前
Python爬虫实战:针对Python官网,精准提取出每一个历史版本的版本号、发布日期以及对应的文档/详情页链接等信息,并最终清洗为标准化的CSV文件!
爬虫·python·爬虫实战·零基础python爬虫教学·python官方数据采集·采集历史版本版本号等信息·导出csv文件
databook1 小时前
像搭积木一样思考:数据科学中的“自下而上”之道
python·数据挖掘·数据分析
luoluoal1 小时前
基于python的医疗问句中的实体识别算法的研究(源码+文档)
python·mysql·django·毕业设计·源码
啊阿狸不会拉杆1 小时前
《机器学习导论》第 9 章-决策树
人工智能·python·算法·决策树·机器学习·数据挖掘·剪枝
喵手1 小时前
Python爬虫实战:城市停车收费标准自动化采集系统 - 让停车费透明化的技术实践(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·城市停车收费标准·采集城市停车收费数据·采集停车数据csv文件导出
无水先生1 小时前
python函数的参数管理(01)*args和**kwargs
开发语言·python