来源:Python技巧 | 一个任务超时退出的装饰器,用起来真方便~

本篇装饰器的写法,倒是蛮值得学习的,贴一下。

文章目录

  • 1 任务超时退出
  • 2 日志记录
  • 3 缓存
  • 4 约束某个函数的可执行次数

1 任务超时退出

我们日常在使用的各种网络请求库时都带有timeout参数,例如request库。这个参数可以使请求超时就不再继续了,直接抛出超时错误,避免等太久。

如果我们自己开发的方法也希望增加这个功能,该如何做呢?

方法很多,但最简单直接的是使用并发库futures,为了使用方便,我将其封装成了一个装饰器,代码如下:

import functools
from concurrent import futuresexecutor = futures.ThreadPoolExecutor(1)def timeout(seconds):def decorator(func):@functools.wraps(func)def wrapper(*args, **kw):future = executor.submit(func, *args, **kw)return future.result(timeout=seconds)return wrapperreturn decorator

定义了以上函数,我们就有了一个超时结束的装饰器,下面可以测试一下:

import time@timeout(1)
def task(a, b):time.sleep(1.2)return a+btask(2, 3)

结果:

---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
...
D:\Anaconda3\lib\concurrent\futures\_base.py in result(self, timeout)432                 return self.__get_result()433             else:
--> 434                 raise TimeoutError()435 436     def exception(self, timeout=None):TimeoutError:

上面我们通过装饰器定义了函数的超时时间为1秒,通过睡眠模拟函数执行超过1秒时,成功的抛出了超时异常。

程序能够在超时时间内完成时:

@timeout(1)
def task(a, b):time.sleep(0.9)return a+btask(2, 3)

结果:

5

可以看到,顺利的得到了结果。

这样我们就可以通过一个装饰器给任何函数增加超时时间,这个函数在规定时间内还处理不完就可以直接结束任务。

前面我将这个装饰器将所需的变量定义到了外部,其实我们还可以通过类装饰器进一步封装,代码如下:

import functools
from concurrent import futuresclass timeout:__executor = futures.ThreadPoolExecutor(1)def __init__(self, seconds):self.seconds = secondsdef __call__(self, func):@functools.wraps(func)def wrapper(*args, **kw):future = timeout.__executor.submit(func, *args, **kw)return future.result(timeout=self.seconds)return wrapper

经测试使用类装饰器能得到同样的效果。


2 日志记录

如果我们需要记录部分函数的执行时间,函数执行前后打印一些日志,装饰器是一种很方便的选择。

代码如下:

import time
import functoolsdef log(func):@functools.wraps(func)def wrapper(*args, **kwargs):start = time.perf_counter()res = func(*args, **kwargs)end = time.perf_counter()print(f'函数 {func.__name__} 耗时 {(end - start) * 1000} ms')return resreturn wrapper

装饰器 log 记录某个函数的运行时间,并返回其执行结果。

测试一下:

@log
def now():print('2021-7-1')now()

结果:

2021-7-1
函数 now 耗时 0.09933599994838005 ms

3 缓存

如果经常调用一个函数,而且参数经常会产生重复,如果把结果缓存起来,下次调用同样参数时就会节省处理时间。

定义函数:

import math
import random
import timedef task(x):time.sleep(0.01)return round(math.log(x**3 / 15), 4)

执行:

%%time
for i in range(500):task(random.randrange(5, 10))

结果:

Wall time: 5.01 s

此时如果我们使用缓存的效果就会大不一样,实现缓存的装饰器有很多,我就不重复造轮子了,这里使用functools包下的LRU缓存:

from functools import lru_cache@lru_cache()
def task(x):time.sleep(0.01)return round(math.log(x**3 / 15), 4)

执行:

%%time
for i in range(500):task(random.randrange(5, 10))

结果:

Wall time: 50 ms

4 约束某个函数的可执行次数

如果我们希望程序中的某个函数在整个程序的生命周期中只执行一次或N次,可以写一个这样的装饰器:

import functoolsclass allow_count:def __init__(self, count):self.count = countself.i = 0def __call__(self, func):@functools.wraps(func)def wrapper(*args, **kw):if self.i >= self.count:returnself.i += 1return func(*args, **kw)return wrapper

测试:

@allow_count(3)
def job(x):x += 1return xfor i in range(5):print(job(i))

结果:

1
2
3
None
None

[转载]一个任务超时退出的装饰器,用起来真方便相关推荐

  1. [转载] python迭代器、生成器和装饰器

    参考链接: 有效地在Python中使用迭代 文章目录 生成器生成器表达式(generator expression)通过使用yield关键字定义生成器并行前戏高潮 迭代器迭代器概述iter()函数 创 ...

  2. 一个初学者的辛酸路程-装饰器-5

    前言: 继续前进 基础回顾: 1.集合 集合有2个重要作用:关系测试(并集,差集,交集)和去重. 2.文件编码 2.7上默认文件编码是ASCII码,因为不支持中文,就出了GB2312,在2.7上要支持 ...

  3. python超时退出进程_Python如何实现让一个函数超时退出?

    你的意思是函数一直在做cpu密集型的计算任务吗?可以把任务分割,执行完一个小任务后检查是否超时,超时return,否则继续. 补充: 这样吧 # coding=utf-8 import datetim ...

  4. python超时处理_Python如何实现让一个函数超时退出?

    你的意思是函数一直在做cpu密集型的计算任务吗?可以把任务分割,执行完一个小任务后检查是否超时,超时return,否则继续. 补充: 这样吧 # coding=utf-8 import datetim ...

  5. [转载]理解PYTHON中的装饰器

    [翻译]理解PYTHON中的装饰器 来源stackoverflow上的问题 链接 python的函数是对象 要理解装饰器,首先,你必须明白,在python中,函数是对象. 这很重要. 简单例子来理解为 ...

  6. python之装饰器详解

    这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...

  7. Python 装饰器 函数

    Python装饰器学习(九步入门):http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 浅谈Python装饰器:https://b ...

  8. Python 装饰器详解(上)

    Python 装饰器详解(上) 转自:https://blog.csdn.net/qq_27825451/article/details/84396970,博主仅对其中 demo 实现中不适合pyth ...

  9. python两层装饰器_python装饰器

    Python的装饰器的英文名叫Decorator,基本上适用的场景就是"装修":不涉及主流程业务,用于鉴权.审计等副业. 1.函数 在python中,函数通过def关键字.函数名和 ...

最新文章

  1. fscanf()函数具体解释
  2. ASP.NET WebAPi之断点续传下载(中)
  3. 四、数据挖掘中常见的挖掘模式
  4. HDU 4618 - Palindrome Sub-Array(2013MUTC2-1008)(DP)
  5. 使用AspectCore动态代理
  6. 从零开始学视觉Transformer(3):视觉问题中的注意力机制
  7. java sqlite 操作_Java SQLite 数据库操作
  8. php mysql 多行_php-更新MySQL中的多行而没有循环
  9. [MATLAB]设置坐标轴标签
  10. ubuntu 配置python,Redis,Mysql
  11. Android之——图片的内存优化
  12. 使用DbFunctions来解决EF按照日期分组数据
  13. os+rom+android+6.0+n9005,三星S8+官方韩版安卓9固件rom系统线刷升级包:G955NKSU3DSG5
  14. __stdcall的作用及今天的坑
  15. 颜色模式,tiff,rgb2cmyk
  16. JVM-G1垃圾回收器:G1回收流程(Rset、CSet、SATB)
  17. 戴尔R710服务器配置raid阵列(附图文)
  18. 【UE4 第一人称射击游戏】12-全自动步枪并显示剩余弹药量
  19. 北漂95后的2020年
  20. VMware虚拟机对外暴露ip的操作

热门文章

  1. 正则表达式的学习使用
  2. poj 1562 简单 bfs
  3. HTML 4.01/XHTML 1.0标签列表
  4. PowerPoint 蜜蜂跳“8”字舞实例
  5. 多数据点拟合曲线,最小二乘法,矩阵
  6. 结对编程-四则运算生成
  7. 我与电脑1-初识电脑
  8. ssh登录 The authenticity of host 192.168.0.xxx can't be established. 的问题
  9. 实现两个虚拟域内用户相互收发邮件
  10. 一天一种设计模式之二-----备忘录模式