python的classmethod类方法和property描述符

在学习的过程中偶然发现classmethod常常与property连用的情况,但是不理解底层的逻辑,以下是我总结过后的一些简单应用

property的应用(定制延迟计算)

因为对象属性执行的优先级是数据描述符(定义了__get__方法而且至少有有__delete__,__set__方法中的任何一个)>实例对象>非数据描述符(只定义了__get__方法)>类对象,所以计算了一次area之后,会将计算的值res保存在实例对象的属性中,因为实例对象>非数据描述符,计算了一次之后,再调用返回的都是r3实例的area实例属性,使得计算的方法area只调用了一次,可以节省一定的运行速度

classmethod,以下给出了类似官方代码的逻辑

>>> class ClassMethod:
	def __init__(self,f):
		self.f = f
	def __get__(self,obj,cls=None):
		if cls is None:
			print('旺财')
			cls = type(obj)
		if hasattr(type(self.f),'__get__'):
			print(f'来福,{type(self.f)}')
			print(cls)
			return self.f.__get__(cls,cls)
		return 0

	
>>> class D:
	@ClassMethod
	@property
	def __doc__(cls):
		return f"class is::{cls.__name__}"

	
>>> d = D()
>>> d.__doc__
来福,<class 'property'>
<class '__main__.D'>
'class is::D'

可见,先将类D中的__doc__方法变成property描述符,再将该描述符当作函数参数传入classmethod中,首先我们要思考,为什么classmethod能真正将cls参数变成类对象呢?它只是把self改成了cls,就改了个名称是怎么做到的?

答案是在ClassMethod类中的if语句if cls is None(我也不理解为什么要将参数cls默认为None,设不设置cls参数都会是类D这个类对象),最后将类D赋值给cls变量,使得在下一行if语句中,输出self.f.__get__(cls,cls),因为这里的self.f是property对象,把cls参数传给了property对象__get__中第一个(这个参数并没有发生作用,只是一个占位)和第二个参数(这个参数才是把cls类对象传给了__doc__方法中的参数cls),所以发生参数改变的原因就是在ClassMethod方法中实现的

下面是property和classmethod的简单运用

通过自定义描述符记录该实例对象调用某个函数的次数

# 测量该类的对象该函数调用的次数
class Class_Property:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        instance.func1_count += 1
        return self.func(instance)


class C:
    def __init__(self):
        self.func1_count = 0

    @Class_Property
    def func1(self):
        print('func1')


c = C()
c.func1
c.func1
c.func1
print(c.func1_count)

# 运行结果
func1
func1
func1
3

通过添加classmethod,计算该类的某个函数被对象调用的次数

# 测量该类的某个函数被调用的次数
class Class_Property:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        instance.func1_count += 1
        return self.func(instance)


class C:
    func1_count = 0
    @classmethod
    @Class_Property
    def func1(cls):
        print('func1')
c = C()
c.func1
c.func1
c.func1
print(C.func1_count)


# 运行结果
func1
func1
func1
3

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值