61、Python之函数高级:为函数添加方法,实现属性可变的装饰器

2024-09-05 07:12

本文主要是介绍61、Python之函数高级:为函数添加方法,实现属性可变的装饰器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

今天文章的标题,初读起来可能有些拗口,什么叫“为函数添加方法”?但是,如果真正对“Python函数也是对象”这个理念有清晰的理解的话,其实,也是不难理解的,本质上就是给一个对象新增一个自定义方法。通过这样做,我们就可以实现在运行过程中,对装饰器的属性进行动态修改了。

本文的主要内容有:

1、函数对象添加自定义方法

2、属性可变的动态装饰器

函数对象添加自定义方法

其实,这一点比较简单,只需要把函数当作Python中的一个普通对象即可。但是,如果一直执着于函数本身,则理解起来,会有些拧巴。

我们来演示下给函数添加自定义方法的做法,直接看代码:

def add(a, b):base = 0if hasattr(globals()['add'], 'base'):base = globals()['add'].baseprint('执行加法运算')return base + a + bdef change_base(x):globals()['add'].base = xprint(f'变更后:add.base={x}')print(add(10, 20))
print('=' * 20)
add.change_base = change_base
add.change_base(100)
print('=' * 20)
print(add(10, 20))

执行结果:

dbbcf4d0d79da1ad4f305adc3ceb1f82.jpeg

首先要说明的,这是一个很拧巴的把函数当作普通对象进行使用的演示代码。

可以看到,我们给函数对象添加了一个change_base()的方法,用于修改add函数对象的base属性(当然,如果不存在base属性,就会动态添加一个base属性)。

属性可变的动态装饰器

既然在Python中一个函数对象可以当作普通对象使用,动态添加属性和方法都是可以的。那么,我们基于这样的特性,就可以进一步扩充作为装饰器的闭包函数对象,实现动态修改闭包属性的效果。

假设有这样一个业务需求,还是基于免费用户、普通vip、超级vip的用户的区分。免费用户转换为vip/svip门槛有些高,我们为了提高营收,增加了这样一项功能:支持免费用户按次付费,体验vip、svip的功能体验,从而增加付费用户的转化率。

这个业务需求,就需要我们在免费用户单次付费后,动态调整延迟时长了,也就是我们本文的主角:属性可变的动态装饰器。

我们稍微简化一下,之前的代码,简单定义一个延迟的装饰器,然后模拟付费体验一次的场景实现:

import timedef wait(func):paid = Falsedef wrap(*args, **kwargs):nonlocal paidif paid:print('使用专属付费渠道')paid = Falseelse:print('免费用户排队中...')time.sleep(5)return func(*args, **kwargs)def pay_once():nonlocal paidpaid = Truewrap.pay_once = pay_oncereturn wrap@wait
def business():print("开展正常业务")if __name__ == '__main__':print('付费体验前:')business()print('=' * 20)print('付费体验一次vip:')business.pay_once()business()print('=' * 20)print('付费体验一次vip用完后:')business()

执行结果:

78556ec6a56b56718e2f0a8890d81cca.jpeg

从执行结果,可以看到,已经模拟出了付费体验一次vip功能,之后立马又是免费的排队模式的场景。

值得注意的点有:

1、由于后续访问的都是闭包内部的函数对象,也就是wrap,所以,定义了pay_once()的方法,也是要绑定到wrap对象的,所以,才会有:wrap.pay_once = pay_once这行代码,不然,根本没法调用pay_once()方法。

2、这个装饰器通过有点拧巴的组合实现了一个修改闭包状态、使用闭包状态的功能的组合,wrap本身用于访问闭包中的自由变量paid,pay_once()用于修改paid。

3、在内部函数中要修改闭包中的自由变量paid,需要首先通过nonlocal关键字进行声明,否则会被Python解释器当作再内部函数定义一个局部变量paid。

从效果来看,本身就是通过闭包的使用,在模拟实现普通对象的对属性的读写操作的组合。虽然有些拧巴,但是,如果已经掌握了装饰器、闭包的概念,理解起来,也是比较简单的。

总结

本文通过实例代码再次验证了Python中的函数也是对象的理念,同时,明确了函数不是只能作为可调用对象进行函数调用的操作,也可以像普通对象一样,进行动态属性、方法的添加。最后,通过函数对象动态添加方法的机制,实现了一个属性可变的装饰器,实现更加灵活的业务场景需求。

感谢您的拨冗阅读,希望对您有些许帮助!

9bed6215651668339872cc1c48397ca4.jpeg

这篇关于61、Python之函数高级:为函数添加方法,实现属性可变的装饰器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138294

相关文章

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤