【Python】Python同时使用@property和@classmethod

首先给出代码,其中元类“MyMetaclass”的第三个方法“property_classMethod”同时实现了@property和classmethod,print函数的结果注释在对应语句后面。

class MyMetaclass(type):
    __myDict = {'a': 1, 'b': 2}

    @classmethod
    def classMethod(cls, key):
        return cls.__myDict.get(key, 0)

    @property
    def propertyMethod(self):
        return 1

    @property
    def property_classMethod(cls):
        return cls.__myDict


class Myclass(metaclass=MyMetaclass):
    pass


print(type(MyMetaclass))  # <class 'type'>
print(type(Myclass))  # <class '__main__.MyMetaclass'>
print(type(Myclass()))  # <class '__main__.Myclass'>

# 调用MyMetaclass类方法
print(MyMetaclass.classMethod('a'))  # 1
# 调用Myclass类方法
print(Myclass.classMethod('a'))  # 1

# 打印MyMetaclass.property_classMethod类型
print(type(MyMetaclass.property_classMethod))  # <class 'property'>
# 打印Myclass.property_classMethod类型
print(type(Myclass.property_classMethod))  # <class 'dict'>

# 调用MyMetaclass类属性
print(MyMetaclass.property_classMethod)  # <property object at 0x000002CEF052A958>
# 调用Myclass类属性
print(Myclass.property_classMethod)  # {'a': 1, 'b': 2}

参考链接_作者:p不忘初心q

个人理解

Python类中有三个常用的装饰器,分别是

  1. @property(使一个方法可以被当成属性调用,常用于直接返回某一不想被修改的属性)
  2. @classmethod(将一个方法定义为类方法,其中第一个参数要修改为cls,使得该方法可以不用实例化即可被调用)
  3. @staticmethod(静态方法,类似于类方法,也可以不用实例化,只不过该方法恰好处于类中)

其中@property和@classmethod较常用于制作Python的库,使得类被调用时可以更灵活、更安全。

@staticmethod
def staticMethod():
	print(1)

@classmethod
def classMethod(cls, key):
    return cls.__myDict.get(key, 0)

@property
def propertyMethod(self):
    return 1

@classmethod常用于一些类无需被实例化的场景,大量使用时该类可以看做是一组方法的集合。而有时又想要使一个直接返回一个私有类属性,换句话说想要在不创建对象的情况下返回一个不想被更改的“类”属性。这时就需要同时使用@property和classmethod,尝试了一下下面的写法,果然不行

@property
@classmethod
def property_classMethod(cls):
    return cls.__myDict

因为带有“cls”并装饰有“@classmethod”的类方法调用时方法必须带有调用括号(),这时该方法才会被绑定到类;
而装饰有“@property”的方法调用时不能带括号(被当做一个属性,not callable),会自动绑定到实例;
因此需要一个实例化对象调用此方法,并使得对象调用时自动绑定到类来实现classmethod。

上面的说法看起来很矛盾,因为前面已经提到了不创建对象,怎么这里又创建对象了呢?直到看到上面那篇博客突然想到还有“元类”这个东西。元类的解释很复杂,想要深入了解的话不是一两句能解释得通的,这里暂且理解为定义类的类,在定义类的时候指定“metaclass”参数即可指定元类。

这里为什么要使用元类呢,因为装饰有“@property”的方法需要实例化对象来调用,而我们又不想创建对象,恰好被元类定义的类也是元类的一个实例(Python特性,详细了解需自行查询),因此我们使用元类定义的类直接调用@property方法相当于元类的对象在调用@property方法。同时因为是现在是对象在调用@property方法,并且在定义方法时添加了“cls”参数,因此程序会自动将该方法绑定到元类,实现了classmethod的功能。

为了验证上面的解释,打印了以下参数

print(type(MyMetaclass))  # <class 'type'>
print(type(Myclass))  # <class '__main__.MyMetaclass'>
print(type(Myclass()))  # <class '__main__.Myclass'>

# 调用MyMetaclass类方法
print(MyMetaclass.classMethod('a'))  # 1
# 调用Myclass类方法
print(Myclass.classMethod('a'))  # 1

# 打印MyMetaclass.property_classMethod类型
print(type(MyMetaclass.property_classMethod))  # 因为没有实例化,所以是<class 'property'>
# 打印Myclass.property_classMethod类型
print(type(Myclass.property_classMethod))  # 因为已经实例化,所以是<class 'dict'>

# 调用MyMetaclass类属性
print(MyMetaclass.property_classMethod)  # <property object at 0x000002CEF052A958>
# 调用Myclass类属性
print(Myclass.property_classMethod)  # {'a': 1, 'b': 2}
  1. MyMetaclass 继承自 type,因此 type(MyMetaclass) 结果是 <class ‘type’>;
  2. Myclass 由 MyMetaclass 创建,因此 Myclass 是 MyMetaclass 的对象,所以 type(Myclass) 结果是 <class ‘main.MyMetaclass’>;
  3. Myclass() 是 Myclass 的对象,因此 type(Myclass()) 结果是 <class ‘main.Myclass’>;
  4. classMethod 是类方法,无论 Myclass 还是 MyMetaclass调用结果都相同;
  5. property_classMethod 是直接返回类属性的类方法,当做属性调用,因为MyMetaclass.property_classMethod 未创建实例,所以返回 <property object at 0x000002CEF052A958> (类型为 <class ‘property’>),表示这个方法没有被调用。而 Myclass.property_classMethod 相当于创建了实例,因此返回该方法的返回值 {‘a’: 1, ‘b’: 2} (类型为 <class ‘dict’>)。

一些个人理解,可能有不对的地方欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@苏丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值