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

南宫理的日志录 2024-10-29 11:28:09
引言

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

本文的主要内容有:

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

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

函数对象添加自定义方法

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

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

执行结果:

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

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

属性可变的动态装饰器

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

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

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

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

执行结果:

从执行结果,可以看到,已经模拟出了付费体验一次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中的函数也是对象的理念,同时,明确了函数不是只能作为可调用对象进行函数调用的操作,也可以像普通对象一样,进行动态属性、方法的添加。最后,通过函数对象动态添加方法的机制,实现了一个属性可变的装饰器,实现更加灵活的业务场景需求。

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

0 阅读:0

南宫理的日志录

简介:深耕IT科技,探索技术与人文的交集