推荐几个牛 X 的 Python 装饰器

【Python函数式编程⑤】——返回函数、闭包、装饰器、偏函数 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。我们在操作函数的时候,如果不需要立刻求和,而是在后面的代码中,根据需要再计算. 阅读详情

任务超时退出

我们日常在使用的各种网络请求库时都带有 timeout 参数,例如:request 库

这个参数可以使请求超时就不再继续了,直接抛出超时错误,避免等太久

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

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

import functools
from concurrent import futures

executor = 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 wrapper
    return decorator

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

import time

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

task(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+b

task(2, 3)

结果:

5

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

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

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

import functools
from concurrent import futures

class timeout:
    __executor = futures.ThreadPoolExecutor(1)

    def __init__(self, seconds):
        self.seconds = seconds

    def __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

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

注意:使用 @functools.wraps 的目的是因为被装饰的 func 函数元信息会被替换为 wrapper 函数的元信息,而 @functools.wraps(func) 将 wrapper 函数的元信息替换为 func 函数的元信息。最终虽然返回的是 wrapper 函数,元信息却依然是原有的 func 函数

在函数式编程中,函数的返回值是函数对象被称为闭包

日志记录

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

代码如下:

import time
import functools
 
def 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 res
    return wrapper

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

测试一下:

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

结果:

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

缓存

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

定义函数:

import math
import random
import time


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: 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

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

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

import functools


class allow_count:
    def __init__(self, count):
        self.count = count
        self.i = 0

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            if self.i >= self.count:
                return
            self.i += 1
            return func(*args, **kw)
        return wrapper

测试:

@allow_count(3)
def job(x):
    x += 1
    return x


for i in range(5):
    print(job(i))

结果:

1
2
3
None
None

爱点赞爱笑的人,运气都不会太差

Java判断地图坐标(经度,纬度)是否在多边形区域或圆形区域内 ​欢迎光临我的博客查看最新文章:在地图上,可以使用经纬度确定一个位置,如上海体育场(121.449391,31.188228),如果知道了2个地点的经纬度,我们就能在地图上找到其位置及2点的距离,百度地图或高德地图提供了相应的服务;如果将多个坐标点连成多边形区域,如何判断某个坐标点是否在多边形区域内,如下工具类。 阅读详情

相关推荐

哨兵2号遥感影像解析全流程:步骤、算法与AI应用详解

未来,多源数据融合与边缘计算技术的应用将进一步拓展遥感解析的边界。波段合成:选择10m分辨率波段(如B2、B3、B4、B8)进行Layer Stacking,生成多光谱影像。| 分类与识别 | Scikit-Learn、PyTorch | SVM、CNN、K-Means聚类 | 地块分类、目标检测 || 数据预处理 | SNAP、Sen2Cor | 大气校正、几何校正 | L2A产品生成、格式转换 || 波段融合 | ENVI、GDAL | Layer Stacking、重采样 | 多光谱影像合成 |

zhz5214的博客 2711

java, golang, python 泛型, 异常, 装饰器等范例讲解

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33675507的博客 197

【AAOS】【源码分析】用户管理(五)-- MUMD介绍

MUMD(多用户多屏显示)是Android Automotive OS为车载多乘员场景设计的功能,支持不同座位用户独立操作各自屏幕。

码农的历程 1511

python装饰器这一篇就够了

python装饰器这一篇就够了

努力下来就凸头 1万+

应广单片机 按键点灯 PMS171B GPIO LED

我也是第一次使用这款单片机,参考网友的资料,写个最近简单的demo 测试用例 #include "extern.h" /*端口定义*/ BIT KEY : PA.0; BIT SW : PA.4; /*相应于main函数*/ void FPPA0 (void) { /*单片机内部RC震动时钟为 IHRC默认为16M,因此,IHRC/2=8M,系统时钟为8M*/ .ADJUST_IC...

大江的专栏 1000

速腾聚创多激光雷达点云采集,并用RVIZ进行显示

在ubuntu20.04系统下,使用速腾聚创官方提供的软件RSView,对激光雷达的默认IP地址、MSOP 包端口号、 DIFOP包端口号和时间模式等配置进行查看和修改。使用交换机对两个激光雷达进行组网,实现多激光雷达数据采集,并用RVIZ同时显示两个雷达点云。使用wireshark对比两个雷达数据包。

abanchao的博客 5888

【python】装饰器详解推荐

复杂道理浅中来,见过的解释最清楚的一篇文章: https://blog.youkuaiyun.com/xiangxianghehe/article/details/77170585

weixin_33834910的博客 119

别再为H5扫码头疼了!用Vue3 + vue-qrcode-reader,5分钟搞定移动端摄像头调用(附完整代码)

本文详细介绍了如何使用Vue3和vue-qrcode-reader快速实现移动端扫码功能,解决H5开发中常见的摄像头调用和兼容性问题。通过完整的代码示例和优化技巧,帮助开发者高效集成二维码识别功能,提升用户体验和开发效率。

weixin_33737134的博客 514

python基础|开发一个任务超时退出的装饰器

在我们日常使用的各种网络请求库都带有timeout参数,超时就不再继续请求了,避免等太久。 如果我们自己开发的方法也希望增加这个功能,该如何做呢?答案是线程池futures,为了使用方便,我将其封装成了一个装饰器,代码如下: import functools from concurrent import futures import time executor = futures.ThreadPoolExecutor(1) def timeout(seconds): def decorator(

小小明-代码实体的专栏 4万+

PMOS缓启动电路设计实战:用LTspice优化上电时序,把60A冲击降到15A

本文通过一个实战案例,深入解析了PMOS缓启动电路如何有效抑制上电冲击电流。文章指出,低ESR电容是导致冲击电流飙升的元凶,并详细阐述了利用LTspice仿真工具,通过优化栅极电阻和栅源电容等参数,将高达60A的冲击电流成功降至15A的设计与优化过程,为电源开关电路设计提供了可复用的方法论。

onion的博客 899

YOLOv11 改进入门篇 | 轻量级涨点技巧:GhostConv 替代普通卷积的实战指南

摘要: 本文介绍如何通过GhostConv改进YOLOv11,实现轻量化涨点。YOLOv11深度增加导致参数量、延迟和内存占用上升,GhostConv通过“本征特征+线性变换”策略,在精度几乎无损的情况下降低30%-50%计算量。文章详细解析GhostConv原理,对比普通卷积的参数量和FLOPs优势,并提供完整的代码级改造流程,包括模块实现、注册及网络配置。实验表明,该方法有效提升边缘端推理效率,适用于移动端等资源受限场景。

shrgegrb的博客 1655

go中装饰器初探

虽然对于动态类型的语言,比如python或者js里,装饰器模式已经很常用 go中的函数是一等公民,可以直接作为参数传入传出,装饰器是可行的 但go的问题是静态类型,func addAllInt(a …int) 和 func addAllStr(a …string)是不同的类型。本身作为装饰器函数,只能传入出入参数一致的同类型的函数,这样限制了装饰器的应用场景。为了兼容通用的类型,需要使用反射来做一些事,但真正实现起来,却踩了不少坑,蛮有难度 需求: go的协程一旦发生panic,就只能在自己的协程里捕获,一

Rainy Chan 727

Open3D 计算点云配准的旋转和平移误差

通过计算旋转误差和平移误差来量化配准结果与真实变换之间的偏差。

点云侠的博客 251

推荐 8 个炫酷的 Python 装饰器

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。它还包含比这个装饰器更酷的功能,但这个装饰器肯定是我最喜欢的。

m0_61408947的博客 966

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

推荐8个炫酷的 Python 装饰器!

Python 编程语言的一大优点是它把所有功能都打包到一个小包中,这些功能非常有用。许多特性可以完全改变 Python 代码的功能,这使得该语言更加灵活。如果使用得当,其中一些功能可以有效...

大江狗 797

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

超棒!推荐 8 个炫酷的 Python 装饰器!

Python 编程语言的一大优点是它把所有功能都打包到一个小包中,这些功能非常有用。许多特性可以完全改变 Python 代码的功能,这使得该语言更加灵活。如果使用得当,其中一些功能可以有效缩短编写程序所需的时间。实现这些目标的一个很好的例子是 Python 的装饰器。

Trb401012的博客 1288

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

python闭包和装饰器的区别_python中闭包和装饰器

前言:编程语言发展的过程中,我们为了提高代码利用率,发明了函数式编程。函数将代码封装起来,我们需要用到此功能函数的时候,调用一下就可以了。但是使用的过程中,也遇到了一些问题,比如函数实现的功能不够,或者跟我们要实现的功能有些差别。肿么办呢?打开函数内部代码,重新写?可以吗?可以!但是这就违背了函数式编程思想的初衷,代码没有重复利用,而且还破坏了原有函数代码。怎么办?聪明的人类思想的灯泡再次闪亮,咔...

weixin_34431283的博客 2326

Python 装饰器为什么要双层嵌套

参考链接: python装饰器为什么要双层嵌套函数 python装饰器为什么要双层嵌套 从上述回答中的几个有助于装饰器理解的 关键点: 装饰器发生在 定义 阶段而不是 执行 阶段。 装饰器返回的是一个被装饰过的 函数定义。 结合第二点理解now = foo(now)。 原因: 如果没有嵌套,实际上装饰器返回的要么是原函数的定义,要么根本不是函数,也就是说函数根本没有被装饰。 即使碰巧得到了...

zhengyajun_email的博客 1658

python 装饰器有哪些_python装饰器是什么

首先,什么是装饰器?比较官方的解释是:装饰器是用来管理和调用函数和类的一个可调用对象,也就是说分为函数装饰器和类装饰器这个定义函数我自己通俗化了一点,不然更加看不懂,其实我还有一句更加概括的话,可以解释装饰器:装饰器就是对被装饰的对象(函数、类)进行重构的,其可以在不改变原来对象的情况下调用对象时执行重构后的行为这里你可能就糊涂了,看不懂没关系我们慢慢来!!!首先,装饰器的语法你肯定知道def d...

weixin_39970064的博客 331

浅析python中@装饰器的作用

要了解python中@装饰器的作用,首先要记住这么几点: 1. 装饰器符号“@”属于语法糖,什么意思呢?就是说,我不按照@装饰器的语法要求来写,而是按照一般python的语法要求来写完全可以。那么用@装饰器的格式来写的目的就是为了书写简单方便 2. 装饰器的作用是什么呢? 简单的理解就是:装饰原有的函数。什么意思呢?比如有一个函数func(a, b),它的功能是求a,b的差值,我现在有一个需求

star714的博客 1万+

python中的装饰器

目录1.装饰器定义2.装饰器的功能3. 装饰器的实际应用 1.装饰器定义 把一个函数当作参数,返回一个替代版的函数 本质上就是一个返回函数的函数 作用:在不改变原函数的基础上,给函数增加功能 2.装饰器的功能 案例一: 装饰器的使用 案例二: 使用装饰器给函数增添新的功,在已经写好的函数上添加新内容 案例三: 装饰器传入参数 案例四: 装饰器设置可变参数 案例五: 装饰器可以设置关键字...

rrrr_ffff的博客 789

Python装饰器的另类用法

value.append(i*i)return valueprint len(table), table[3] # 5 9@call()装饰器适用于任何函数,你传入的参数会被直接使用然后结果赋值给同名函数。这样避免了你重新定义一个变量来存储结果。@list 装饰器假如你有一个这样一个生成器函数。def table(n):for i in range(n):yield i当你要生成n=5的序列时,可以直接调用。table = table(5)print table #

2401_84010302的博客 517
上一篇: 老师吴恩达,身家又增20亿!
下一篇: 300 页图解网络.pdf (附下载)
菜鸟学Python
博客等级 码龄9年 8061粉丝 571原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值