由于看python代码里面函数上的@ 不爽很久了,为了避免自己又忘记了这里来记录下。
简单总结:
@ 的作用就是在使用 @ 下面的函数(如下图的cs2)的时候,会在该函数执行前将该函数作为参数扔到@后跟着的处理函数先行处理(或预备处理)些东西,如下图的 time_cs 就是本文举的封装一个计时函数的装饰器的日志。
阅读下面代码对比使用语法糖的使用,即可了解。
本篇博客自参考b站大佬up的视频
区分a()和a如下
一个是: 函数a在电脑中的十六进制地址
一个是: 函数a返回的值
def a():return 1print(a) # 函数a在电脑中的十六进制地址
print(a()) # 函数a返回的值
输出
1
def a():return "a的返回"def b():return "b的返回"def out(action):"""传入函数对象"""print(action())out(a)
out(b)
输出
a的返回
b的返回
即检测的目标函数没有输入值也没有返回值的情况
import timedef time_cs(func):""":param func: 传入的你需要计时的函数:return: 无"""print("开始计时,打下时间戳")start = time.perf_counter()func()end = time.perf_counter()print("完成计时,消耗时间" + str(end-start))print("\n")def cs():print("\n")print("*"*8 + "fun" + "*"*8)print("只是打印当前信息的测试函数")print("*" * 20)print("\n")time.sleep(0.25)time_cs(cs)
输出
开始计时,打下时间戳********fun********
只是打印当前信息的测试函数
********************完成计时,消耗时间0.2602558
即目标函数拥有返回值的情况
这里比较麻烦需要在time_cs 函数中将返回值用一个变量存储,使得你需要预先知道目标函数返回值的个数
import timedef time_cs(func):""":param func: 传入的你需要计时的函数:return: func函数的输出"""print("开始计时,打下时间戳")start = time.perf_counter()num = func()end = time.perf_counter()print("完成计时,消耗时间" + str(end-start))print("\n")return numdef cs2():print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的10")print("*" * 20)print("\n")time.sleep(0.25)return 10def cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))cs3(time_cs(cs2))
输出
开始计时,打下时间戳********fun2********
打印当前信息的测试函数,并返回一个整形的10
********************完成计时,消耗时间0.257934cs3函数得到了cs2函数的输出:10进程已结束,退出代码 0
即目标函数拥有有输入有输出返回值的情况,
首先展示一个能运行但是,无法成功获得目标函数运行时间的写法,这里time_cs输出内部输出由result = func()改成了 result = func
import timedef time_cs(func):""":param func: 传入的你需要计时的函数:return: func函数的输出"""print("开始计时,打下时间戳")start = time.perf_counter()result = func # 注意这里!!不是 func()!!print("传入的函数的id: " + str(id(func)))end = time.perf_counter()print("完成计时,消耗时间" + str(end - start))print("\n")return resultdef cs2(num):print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的" + str(num))print("*" * 20)print("\n")time.sleep(0.25)return numdef cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))num = time_cs(cs2(5))
cs3(num)
输出如下,可以看到该写法下的消耗时间统计是错误的
原因:传入的时候就是传入了一个 cs2(5) 即一个完成了执行了time.sleep(0.25) 之后的程序进入,因此下面输出的9.900000000007125e-06 代表的时间实际就可以理解成输入的func函数运行时间为0时,time_cs函数自身的运行时间
********fun2********
打印当前信息的测试函数,并返回一个整形的5
********************开始计时,打下时间戳
传入的函数的id: 140720369607200
完成计时,消耗时间9.900000000007125e-06cs3函数得到了cs2函数的输出:5
import timedef time_cs(func,num):""":param func: 传入的你需要计时的函数:return: func函数的输出"""print("开始计时,打下时间戳")start = time.perf_counter()result = func(num)print("传入的函数的id: " + str(id(func)))end = time.perf_counter()print("完成计时,消耗时间" + str(end - start))print("\n")return resultdef cs2(num):print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的" + str(num))print("*" * 20)print("\n")time.sleep(0.25)return numdef cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))num = time_cs(cs2,5)
cs3(num)
输出
开始计时,打下时间戳********fun2********
打印当前信息的测试函数,并返回一个整形的5
********************传入的函数的id: 2832141314952
完成计时,消耗时间0.2586813cs3函数得到了cs2函数的输出:5
(目标函数拥有输入有输出)
这里将time_cs这个统计输入函数运行时间的功能函数,改造成输入和输出都是函数 的功能函数,这里是最接下面近装饰器写法的,建议与下面的2.使用装饰器的写法对比看
import time
import functoolsdef time_cs(func):""":param func: 传入的你需要计时的函数:return: func函数的输出"""def my_wrapper(*args, **kwargs):"""再创建一个装饰器函数"""print("开始计时,打下时间戳")start = time.perf_counter()result = func(*args, **kwargs)print("传入的函数的id: " + str(id(func)))end = time.perf_counter()print("完成计时,消耗时间" + str(end - start))print("\n")return resultreturn my_wrapperdef cs2(num):print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的" + str(num))print("*" * 20)print("\n")time.sleep(0.25)return numdef cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))cs2_2 = time_cs(cs2)
cs3(cs2_2(5))
print("传出的函数的id: " + str(id(cs2_2)))
print("传出的函数的名字: " + str(cs2_2.__name__)) # 不加 @functools.wraps(func) 就是输出my_wrapper
输出
开始计时,打下时间戳********fun2********
打印当前信息的测试函数,并返回一个整形的5
********************传入的函数的id: 1392449547432
完成计时,消耗时间0.2594437cs3函数得到了cs2函数的输出:5
传出的函数的id: 1392449545992
传出的函数的名字: my_wrapper
如下
import time
import functoolsdef time_cs(func):""":param func: 传入的你需要计时的函数:return: func函数的输出"""@functools.wraps(func) # 这里的作用是使得返回的 my_wrapper 的 .__name__ 名字# 和传入的 func.__name__ 的相同,如下print(cs2_2.__name__)def my_wrapper(*args, **kwargs):"""再创建一个装饰器函数"""print("开始计时,打下时间戳")start = time.perf_counter()result = func(*args, **kwargs)print("传入的函数的id: " + str(id(func)))end = time.perf_counter()print("完成计时,消耗时间" + str(end - start))print("\n")return resultreturn my_wrapperdef cs2(num):print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的" + str(num))print("*" * 20)print("\n")time.sleep(0.25)return numdef cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))cs2_2 = time_cs(cs2)
cs3(cs2_2(5))
print("传出的函数的id: " + str(id(cs2_2)))
print("传出的函数的名字: " + str(cs2_2.__name__)) # 不加 @functools.wraps(func) 就是输出my_wrapper
输出
开始计时,打下时间戳********fun2********
打印当前信息的测试函数,并返回一个整形的5
********************传入的函数的id: 2366053213960
完成计时,消耗时间0.2593284cs3函数得到了cs2函数的输出:5
传出的函数的id: 2366053215688
传出的函数的名字: cs2进程已结束,退出代码 0
能够达到以上的效果最接近上面1.3,且使用起来更加的方便
import time
import functoolsdef time_cs(func):""":param func: 传入的你需要计时的函数:return: func函数的输出"""@functools.wraps(func) # 这里的作用是使得返回的 my_wrapper 的 .__name__ 名字# 和传入的 func.__name__ 的相同,如下print(cs2_2.__name__)def my_wrapper(*args, **kwargs):"""再创建一个装饰器函数"""print("开始计时,打下时间戳")start = time.perf_counter()result = func(*args, **kwargs)print("传入的函数的id: " + str(id(func)))end = time.perf_counter()print("完成计时,消耗时间" + str(end - start))print("\n")return resultreturn my_wrapper@time_cs
def cs2(num):print("\n")print("*"*8 + "fun2" + "*"*8)print("打印当前信息的测试函数,并返回一个整形的" + str(num))print("*" * 20)print("\n")time.sleep(0.25)return numdef cs3(num):print("cs3函数得到了cs2函数的输出:" + str(num))cs3(cs2(5))print("传出的函数的名字: " + str(cs2.__name__)) # 不加 @functools.wraps(func) 就是输出my_wrapper
输出
开始计时,打下时间戳********fun2********
打印当前信息的测试函数,并返回一个整形的5
********************传入的函数的id: 2966589466664
完成计时,消耗时间0.26083870000000003cs3函数得到了cs2函数的输出:5
传出的函数的名字: cs2进程已结束,退出代码 0
下班了后面来更新,使用。。。。
import time
import functoolsdef retry_and_show(exception: Exception, tries: int = 3, delay: int = 1, backoff: int = 2):""":param exception: 错误;类型:param tries: 重试次数:param delay: 间隔重试时间间隔 秒:param backoff: 回退步长:return:"""def decorator_retry(func):@functools.wraps(func)def run_with_retry_police(*args,**kwargs):_tries, _delay = tries,delaywhile _tries > 1:try:return func(*args,**kwargs)except exception:print("程序错误" + str(_delay) + "秒后重新尝试")time.sleep(_delay)_tries -= 1_delay *= backoffreturn func(* args, ** kwargs)return run_with_retry_policereturn decorator_retry
视频27.58分说明