既然是装饰器, 肯定就是跟设计模式中的装饰模式有关了
装饰器就是python 中对装饰模式的一种注解实现,令其可以对其他函数进行一些功能上的增强。
住这里的增强并不是真正的修改函数的业务逻辑, 只是前后增加一些步骤。
有点类似于java 的AOP(基于动态代理模式)
装饰模式的介绍:
https://blog.csdn.net/nvd11/article/details/41918155?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171493094016800184114116%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171493094016800184114116&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-41918155-null-null.nonecase&utm_term=%E8%A3%85%E9%A5%B0&spm=1018.2226.3001.4450
编写1个函数, 可以build 1个100万个随即数字的数组
import random
from loguru import logger
import tracemalloc
import time
def sample1():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample1()
执行:
2024-05-06 01:29:13.314 | INFO | __main__:sample1:7 - len of list_num is 10000000
需求, 修改这个函数, 在执行开始前输出执行开始时间, 执行后输出执行多长时间以及内存占用
那我们修改一下:
import random
from loguru import logger
import tracemalloc
import time
def sample2():
tracemalloc.start()
start_time = time.time()
logger.info("Start time is {}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))))
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
# print the memory usage
current_mem, peak_mem = tracemalloc.get_traced_memory();
logger.info("Current memory usage is {}MB; Peak was {}MB".format(current_mem / 10**6, peak_mem / 10**6))
tracemalloc.stop
# print the time usage
end_time = time.time()
logger.info("End time is {}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))))
logger.info("Time used is {} seconds".format(end_time - start_time))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample2()
输出:
import random
from loguru import logger
import tracemalloc
import time
def sample1():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample1()
咋一看不怎么复杂, 无非在函数内的核心代码前后添加一些 time 和 mem usage 的信息收集代码
但是假如你的line manager 要求你把某个项目的多个函数都加上这个功能。 那你怎么办, 一个一个函数去修改吗?
这时就可以利用装饰器去实现了
python 可以另1个函数 作为另1个函数的一个参数
跟javascript 一样, 而不需要像java 那样利用接口实现
举个例子:
def sample_callback():
rs = cal_numbers(1, 2 ,3, call_back=avg_call_back)
logger.info("avg is {}".format(rs))
rs = cal_numbers(1, 2 ,3, 4, call_back=max_call_back)
logger.info("max num is {}".format(rs))
rs = cal_numbers(1, 2, 3, 4, 5 , call_back=lambda *args: sum(args) / len(args))
logger.info("avg is {}".format(rs))
def cal_numbers(*args, call_back = None):
if call_back:
return call_back(*args)
else:
return sum(args)
pass
def avg_call_back(*args):
return sum(args) / len(args)
def max_call_back(*args):
return max(args)
if __name__ == "__main__":
import src.configs.config
sample_callback()
上面例子中, avg_call_back 函数 he max_call_back 就是作为1个参数传入 cal_numbers
甚至可以用lambda 构建1个 匿名函数作为参数
这个特性是构造python 装饰器的一个前提
构建1个简单的装饰器
from loguru import logger
def print_info(func):
logger.info("print_info is used for function {}".format(func.__name__))
def wrapper(*args, **kwargs):
logger.info.infont("Function {} is going to be called".format(func.__name__))
rs = func(*args, **kwargs)
logger.info("Function {} is called".format(func.__name__))
return rs
logger.info("print_info is defined done for function {}".format(func.__name__))
return wrapper
如何使用这个装饰器呢
第一个方法是 用装饰器去包装原方法, 因为print_info 的参数是1个函数嘛
例子:
import random
from loguru import logger
import tracemalloc
import time
from src.decorator.print_info import print_info
def sample3_1():
# build a list of 2000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def sample3_2():
# build a list of 3000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(3000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def run_sample3():
sample = print_info(sample3_1)
sample()
sample = print_info(sample3_2)
sample()
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
run_sample3()
输出:
2024-05-06 03:50:29.334 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 03:50:29.334 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 03:50:29.334 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function sample3_1
2024-05-06 03:50:29.334 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function sample3_1
2024-05-06 03:50:29.335 | INFO | src.decorator.print_info:wrapper:7 - Function sample3_1 is going to be called
2024-05-06 03:50:29.974 | INFO | __main__:sample3_1:11 - len of list_num is 2000000
2024-05-06 03:50:29.978 | INFO | src.decorator.print_info:wrapper:9 - Function sample3_1 is called
2024-05-06 03:50:29.979 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function sample3_2
2024-05-06 03:50:29.979 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function sample3_2
2024-05-06 03:50:29.979 | INFO | src.decorator.print_info:wrapper:7 - Function sample3_2 is going to be called
2024-05-06 03:50:30.932 | INFO | __main__:sample3_2:16 - len of list_num is 3000000
2024-05-06 03:50:30.935 | INFO | src.decorator.print_info:wrapper:9 - Function sample3_2 is called
注意日志的打印顺序
先是print_info defined
然后才是 going to be called
然后函数执行
最后是function is called
使用注解来调用装饰器
其实上面的写法
sample = print_info(sample3_1)
sample()
sample = print_info(sample3_2)
sample()
调用装饰器的方法并不常用, 在项目中也不是很方便, 还是要查找被修改的函数的所有引用, 可能还是会改动 很多个地方。
实际上, 装饰器是用在注解上的
修改后代码如下:
import random
from loguru import logger
import tracemalloc
import time
from src.decorator.print_info import print_info
@print_info
def sample4_1():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
@print_info
def sample4_2():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(3000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample4_1()
sample4_2()
这次直接把print_info 作为 注解添加到要使用的函数上
实际上python的@注解都是装饰器
输出:
2024-05-06 03:51:03.226 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function sample4_1
2024-05-06 03:51:03.227 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function sample4_1
2024-05-06 03:51:03.227 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function sample4_2
2024-05-06 03:51:03.227 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function sample4_2
project_path is /home/gateman/Projects/python/python_common_import
2024-05-06 03:51:03.242 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 03:51:03.243 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 03:51:03.243 | INFO | src.decorator.print_info:wrapper:7 - Function sample4_1 is going to be called
2024-05-06 03:51:03.886 | INFO | __main__:sample4_1:12 - len of list_num is 2000000
2024-05-06 03:51:03.890 | INFO | src.decorator.print_info:wrapper:9 - Function sample4_1 is called
2024-05-06 03:51:03.890 | INFO | src.decorator.print_info:wrapper:7 - Function sample4_2 is going to be called
2024-05-06 03:51:04.856 | INFO | __main__:sample4_2:18 - len of list_num is 3000000
2024-05-06 03:51:04.858 | INFO | src.decorator.print_info:wrapper:9 - Function sample4_2 is called
注意这次print 的顺序
因为是注解方式, 所以python在执行代码之前首先执行了 print_info的定义部分, 而这时被包装的函数还没有调用, 容器理解
为装饰器添加1层装饰器
上面的装饰器 这是在函数执行前后print 一下信息
如果再增加1个功能, 我们其实可以通过增加装饰器来实现的
我们增加1个print_time的装饰器
print_time.py
from loguru import logger
import time
def print_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
logger.info("Start time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))))
rs = func(*args, **kwargs)
end_time = time.time()
logger.info("End time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))))
logger.info("Time used of {} is {} seconds".format(func.__name__, end_time - start_time))
return rs
return wrapper
如何调用呢
第一种调用方法:
import random
from loguru import logger
import tracemalloc
import time
from src.decorator.print_info import print_info
from src.decorator.print_time import print_time
def sample5():
# build a list of 2000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def run_sample5():
sample = print_time(print_info(sample5))
sample()
logger.info("====================================")
sample = print_info(print_time(sample5))
sample()
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
run_sample5()
注意 这里调用了两次sample5, 分别用print_time, print_info一起包装,但是包装的顺序不同的
输出:
2024-05-06 03:57:50.293 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function sample5
2024-05-06 03:57:50.294 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function sample5
2024-05-06 03:57:50.294 | INFO | src.decorator.print_time:wrapper:6 - Start time of wrapper is 2024-05-06 03:57:50
2024-05-06 03:57:50.294 | INFO | src.decorator.print_info:wrapper:7 - Function sample5 is going to be called
2024-05-06 03:57:50.934 | INFO | __main__:sample5:12 - len of list_num is 2000000
2024-05-06 03:57:50.939 | INFO | src.decorator.print_info:wrapper:9 - Function sample5 is called
2024-05-06 03:57:50.939 | INFO | src.decorator.print_time:wrapper:9 - End time of wrapper is 2024-05-06 03:57:50
2024-05-06 03:57:50.939 | INFO | src.decorator.print_time:wrapper:10 - Time used of wrapper is 0.6454496383666992 seconds
2024-05-06 03:57:50.939 | INFO | __main__:run_sample5:18 - ====================================
2024-05-06 03:57:50.939 | INFO | src.decorator.print_info:print_info:4 - print_info is used for function wrapper
2024-05-06 03:57:50.939 | INFO | src.decorator.print_info:print_info:11 - print_info is defined done for function wrapper
2024-05-06 03:57:50.940 | INFO | src.decorator.print_info:wrapper:7 - Function wrapper is going to be called
2024-05-06 03:57:50.940 | INFO | src.decorator.print_time:wrapper:6 - Start time of sample5 is 2024-05-06 03:57:50
2024-05-06 03:57:51.620 | INFO | __main__:sample5:12 - len of list_num is 2000000
2024-05-06 03:57:51.622 | INFO | src.decorator.print_time:wrapper:9 - End time of sample5 is 2024-05-06 03:57:51
2024-05-06 03:57:51.622 | INFO | src.decorator.print_time:wrapper:10 - Time used of sample5 is 0.682539701461792 seconds
2024-05-06 03:57:51.623 | INFO | src.decorator.print_info:wrapper:9 - Function wrapper is called
很明显, 第一次是 print time 外层, print_info 内层
第二次相反,
对应的调用次序也是不同的
但是有个问题, 外层的装饰器并不能正确获取func._name_ , 其实也不难理解, 因为对于外层里装饰器,参数就是内层的装饰器了, 名字就是wrapper…
解决外层装饰器不能获取源函数名字的问题 - @functools.wraps(func)
很简单, 在内层的装饰器上添加1个 官方装饰器
@functools.wraps(func)
修改后的print_info, 和 print_time
import functools
from loguru import logger
def print_info(func):
logger.info("print_info is used for function {}".format(func.__name__))
@functools.wraps(func)
def wrapper(*args, **kwargs):
logger.info("Function {} is going to be called".format(func.__name__))
rs = func(*args, **kwargs)
logger.info("Function {} is called".format(func.__name__))
return rs
logger.info("print_info is defined done for function {}".format(func.__name__))
return wrapper
from loguru import logger
import time
import functools
def print_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
logger.info("Start time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))))
rs = func(*args, **kwargs)
end_time = time.time()
logger.info("End time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))))
logger.info("Time used of {} is {} seconds".format(func.__name__, end_time - start_time))
return rs
return wrapper
再次执行测试代码:
2024-05-06 04:04:27.783 | INFO | src.decorator.print_info:print_info:5 - print_info is used for function sample5
2024-05-06 04:04:27.783 | INFO | src.decorator.print_info:print_info:14 - print_info is defined done for function sample5
2024-05-06 04:04:27.783 | INFO | src.decorator.print_time:wrapper:9 - Start time of sample5 is 2024-05-06 04:04:27
2024-05-06 04:04:27.783 | INFO | src.decorator.print_info:wrapper:10 - Function sample5 is going to be called
2024-05-06 04:04:28.422 | INFO | __main__:sample5:12 - len of list_num is 2000000
2024-05-06 04:04:28.427 | INFO | src.decorator.print_info:wrapper:12 - Function sample5 is called
2024-05-06 04:04:28.427 | INFO | src.decorator.print_time:wrapper:12 - End time of sample5 is 2024-05-06 04:04:28
2024-05-06 04:04:28.427 | INFO | src.decorator.print_time:wrapper:13 - Time used of sample5 is 0.6437935829162598 seconds
2024-05-06 04:04:28.427 | INFO | __main__:run_sample5:18 - ====================================
2024-05-06 04:04:28.427 | INFO | src.decorator.print_info:print_info:5 - print_info is used for function sample5
2024-05-06 04:04:28.427 | INFO | src.decorator.print_info:print_info:14 - print_info is defined done for function sample5
2024-05-06 04:04:28.427 | INFO | src.decorator.print_info:wrapper:10 - Function sample5 is going to be called
2024-05-06 04:04:28.427 | INFO | src.decorator.print_time:wrapper:9 - Start time of sample5 is 2024-05-06 04:04:28
2024-05-06 04:04:29.096 | INFO | __main__:sample5:12 - len of list_num is 2000000
2024-05-06 04:04:29.099 | INFO | src.decorator.print_time:wrapper:12 - End time of sample5 is 2024-05-06 04:04:29
2024-05-06 04:04:29.099 | INFO | src.decorator.print_time:wrapper:13 - Time used of sample5 is 0.6715624332427979 seconds
2024-05-06 04:04:29.099 | INFO | src.decorator.print_info:wrapper:12 - Function sample5 is calle
问题解决
用注解方式实现多层装饰器
也很简单, 一齐把注解写上去就行
import random
from loguru import logger
import tracemalloc
import time
from src.decorator.print_info import print_info
from src.decorator.print_time import print_time
@print_info
@print_time
def sample6_1():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
@print_time
@print_info
def sample6_2():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(3000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample6_1()
logger.info("====================================")
sample6_2()
同样, 添加注解的顺序也是有影响的
输出:
2024-05-06 04:08:17.287 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 04:08:17.287 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 04:08:17.287 | INFO | src.decorator.print_info:wrapper:10 - Function sample6_1 is going to be called
2024-05-06 04:08:17.287 | INFO | src.decorator.print_time:wrapper:9 - Start time of sample6_1 is 2024-05-06 04:08:17
2024-05-06 04:08:17.916 | INFO | __main__:sample6_1:14 - len of list_num is 2000000
2024-05-06 04:08:17.920 | INFO | src.decorator.print_time:wrapper:12 - End time of sample6_1 is 2024-05-06 04:08:17
2024-05-06 04:08:17.920 | INFO | src.decorator.print_time:wrapper:13 - Time used of sample6_1 is 0.6329360008239746 seconds
2024-05-06 04:08:17.920 | INFO | src.decorator.print_info:wrapper:12 - Function sample6_1 is called
2024-05-06 04:08:17.921 | INFO | __main__:<module>:30 - ====================================
2024-05-06 04:08:17.921 | INFO | src.decorator.print_time:wrapper:9 - Start time of sample6_2 is 2024-05-06 04:08:17
2024-05-06 04:08:17.921 | INFO | src.decorator.print_info:wrapper:10 - Function sample6_2 is going to be called
2024-05-06 04:08:18.907 | INFO | __main__:sample6_2:21 - len of list_num is 3000000
2024-05-06 04:08:18.911 | INFO | src.decorator.print_info:wrapper:12 - Function sample6_2 is called
2024-05-06 04:08:18.911 | INFO | src.decorator.print_time:wrapper:12 - End time of sample6_2 is 2024-05-06 04:08:18
2024-05-06 04:08:18.911 | INFO | src.decorator.print_time:wrapper:13 - Time used of sample6_2 is 0.9907040596008301 seconds
合并多个装饰器成1个装饰器
如果嫌每个方法写多个@注解麻烦
我们可以再添加1个装饰器, 包含print_info 和 print_time
print_info_time.py
import functools
from loguru import logger
from src.decorator.print_info import print_info
from src.decorator.print_time import print_time
def print_info_time(func):
@print_info
@print_time
@functools.wraps(func)
def wrapper(*args, **kwargs):
rs = func(*args, **kwargs)
return rs
return wrapper
在这里我们不再需要重写 业务逻辑, 直接引用 @print_info 和 @print_time就好
当然不想用注解, return wrapper 改成 return print_info(print_time(wrapper)) 也可以
测试:
import random
from loguru import logger
from src.decorator.print_info_time import print_info_time
@print_info_time
def sample7():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample7()
输出:
2024-05-06 04:24:58.113 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 04:24:58.113 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 04:24:58.113 | INFO | src.decorator.print_info:wrapper:10 - Function sample7 is going to be called
2024-05-06 04:24:58.113 | INFO | src.decorator.print_time:wrapper:9 - Start time of sample7 is 2024-05-06 04:24:58
2024-05-06 04:24:58.744 | INFO | __main__:sample7:10 - len of list_num is 2000000
2024-05-06 04:24:58.749 | INFO | src.decorator.print_time:wrapper:12 - End time of sample7 is 2024-05-06 04:24:58
2024-05-06 04:24:58.749 | INFO | src.decorator.print_time:wrapper:13 - Time used of sample7 is 0.6352584362030029 seconds
2024-05-06 04:24:58.749 | INFO | src.decorator.print_info:wrapper:12 - Function sample7 is called
为装饰器添加参数
需求很简单, 在print_time 的装饰器上, 让其接受1个参数 second_limit , 如果 执行时间大于这个指, 则给个warning
这时就要在print_time 装饰器的代码level增加1层了…
修改后
from loguru import logger
import time
import functools
def print_time(second_limit=500):
def print_time_inner(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
logger.info("Start time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))))
rs = func(*args, **kwargs)
end_time = time.time()
logger.info("End time of {} is {}".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))))
logger.info("Time used of {} is {} seconds".format(func.__name__, end_time - start_time))
if end_time - start_time > second_limit:
logger.warning("Time used of {} is more than {} seconds".format(func.__name__, second_limit))
return rs
return wrapper
return print_time_inner
测试:
import random
from loguru import logger
from src.decorator.print_time import print_time
@print_time(second_limit=1)
def sample8():
# build a list of 3000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(4000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample8()
输出:
2024-05-06 05:14:58.547 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 05:14:58.547 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 05:14:58.547 | INFO | src.decorator.print_time:wrapper:10 - Start time of sample8 is 2024-05-06 05:14:58
2024-05-06 05:14:59.917 | INFO | __main__:sample8:10 - len of list_num is 4000000
2024-05-06 05:14:59.925 | INFO | src.decorator.print_time:wrapper:13 - End time of sample8 is 2024-05-06 05:14:59
2024-05-06 05:14:59.925 | INFO | src.decorator.print_time:wrapper:14 - Time used of sample8 is 1.3772785663604736 seconds
2024-05-06 05:14:59.925 | WARNING | src.decorator.print_time:wrapper:16 - Time used of sample8 is more than 1 seconds
Note:
如果 1个装饰器带参数, 则与其他装饰器混用时, 最好带参数, 如果想用默认参数就带()
例如:
def run_sample5():
sample = print_time()(print_info(sample5))
sample()
logger.info("====================================")
sample = print_info(print_time()(sample5))
sample()
注意上面代码print_time() return1个带默认参数的 print_time装饰器 , 然后才接收后面的函数参数
同样的注解也是:
@print_info
@print_time() # 不带括号会出错
def sample6_1():
# build a list of 1000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(2000000)]
logger.info("len of list_num is {}".format(len(list_num)))
用装饰器来实现 统计时间和内存的需求
好了, 终于要实现场景了
其实我们已经写好print_time
我们只需要写多1个print_mem
和1个包住上面两个装饰器的总装饰器 sum_info 就好
print_mem.py
from loguru import logger
import functools
import tracemalloc
def print_mem(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
tracemalloc.start()
rs = func(*args, **kwargs)
# print the memory usage
current_mem, peak_mem = tracemalloc.get_traced_memory();
logger.info("Current memory usage is {}MB; Peak was {}MB".format(current_mem / 10**6, peak_mem / 10**6))
tracemalloc.stop
return rs
return wrapper
sum_info.py
import functools
from loguru import logger
from src.decorator.print_mem import print_mem
from src.decorator.print_time import print_time
def sum_info(func):
@print_time() # here must provide the () otherwise TypeError: print_time.<locals>.decorator() missing 1 required positional argument: 'func'
@print_mem
@functools.wraps(func)
def wrapper(*args, **kwargs):
rs = func(*args, **kwargs)
return rs
return wrapper
测试:
import random
from loguru import logger
from src.decorator.sum_info import sum_info
@sum_info
def sample9():
# build a list of 3000000 numbers ramdomly
list_num = [get_random_number(100) for _ in range(4000000)]
logger.info("len of list_num is {}".format(len(list_num)))
def get_random_number(limit):
return random.randint(0, limit)
if __name__ == "__main__":
import src.configs.config
sample9()
输出:
2024-05-06 05:25:04.225 | INFO | src.configs.config:<module>:19 - basic setup done
2024-05-06 05:25:04.226 | INFO | src.configs.config:<module>:27 - all configs loaded
2024-05-06 05:25:04.226 | INFO | src.decorator.print_time:wrapper:10 - Start time of sample9 is 2024-05-06 05:25:04
2024-05-06 05:25:07.177 | INFO | __main__:sample9:10 - len of list_num is 4000000
2024-05-06 05:25:07.183 | INFO | src.decorator.print_mem:wrapper:14 - Current memory usage is 0.000394MB; Peak was 34.732609MB
2024-05-06 05:25:07.184 | INFO | src.decorator.print_time:wrapper:13 - End time of sample9 is 2024-05-06 05:25:07
2024-05-06 05:25:07.185 | INFO | src.decorator.print_time:wrapper:14 - Time used of sample9 is 2.9584157466888428 seconds