首先给出代码,其中元类“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))
print(type(Myclass))
print(type(Myclass()))
print(MyMetaclass.classMethod('a'))
print(Myclass.classMethod('a'))
print(type(MyMetaclass.property_classMethod))
print(type(Myclass.property_classMethod))
print(MyMetaclass.property_classMethod)
print(Myclass.property_classMethod)
参考链接_作者:p不忘初心q
个人理解
Python类中有三个常用的装饰器,分别是
- @property(使一个方法可以被当成属性调用,常用于直接返回某一不想被修改的属性)
- @classmethod(将一个方法定义为类方法,其中第一个参数要修改为cls,使得该方法可以不用实例化即可被调用)
- @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))
print(type(Myclass))
print(type(Myclass()))
print(MyMetaclass.classMethod('a'))
print(Myclass.classMethod('a'))
print(type(MyMetaclass.property_classMethod))
print(type(Myclass.property_classMethod))
print(MyMetaclass.property_classMethod)
print(Myclass.property_classMethod)
- MyMetaclass 继承自 type,因此 type(MyMetaclass) 结果是 <class ‘type’>;
- Myclass 由 MyMetaclass 创建,因此 Myclass 是 MyMetaclass 的对象,所以 type(Myclass) 结果是 <class ‘main.MyMetaclass’>;
- Myclass() 是 Myclass 的对象,因此 type(Myclass()) 结果是 <class ‘main.Myclass’>;
- classMethod 是类方法,无论 Myclass 还是 MyMetaclass调用结果都相同;
- property_classMethod 是直接返回类属性的类方法,当做属性调用,因为MyMetaclass.property_classMethod 未创建实例,所以返回 <property object at 0x000002CEF052A958> (类型为 <class ‘property’>),表示这个方法没有被调用。而 Myclass.property_classMethod 相当于创建了实例,因此返回该方法的返回值 {‘a’: 1, ‘b’: 2} (类型为 <class ‘dict’>)。
一些个人理解,可能有不对的地方欢迎指出。
|