【数据挖掘】Python的描述器

01

背景


很多Python库中都会出现描述器(descriptor)的身影,Python内置的 staticmethod, classmethod, property,super
等方法也都是描述器。了解描述器协议对于我们理解这些对象的行为会有很大帮助。

02

定义

通常,描述符是具有描述符协议中方法之一的属性值。这些方法是get(),set()和delete()。如果为属性定义了那些方法中的任何一种,则称其为描述符。

如果一个对象定义了以下三个方法中的任意一个,那么这个对象就可以被称之为描述器:

__set__(**)
__get__(**)
__delete__(**)

03

分类

如果对象定义set()或delete(),则将其视为数据描述符。仅定义get()的描述符称为非数据描述符(它们通常用于方法,但也可以用于其他用途)。


描述器又可分为数据描述器(data descriptor)和非数据描述器(non-data descriptor),只有 *get*
方法的对象被称为非数据描述器(non-data desriptor),其他的都称为数据描述器(data descriptor)。

04

使用

下面通过一个例子来展示描述器是怎么使用的。

class PositiveNumber(object):
 
 
    def __init__(self, name, value):
        self.name = name 
        self._value = value
 
    def __get__(self,  obj, dtype):
        return self._value  
 
    def __set__(self,  obj, value):
        if value 
        
            上述代码中的number便是一个描述器。一般来说,描述器是作为另一个对象的属性来出现的:
        
        
class PositiveNumber(object):
 
 
    def __init__(self, name, value):
        self.name = name 
        self._value = value
 
    def __get__(self,  obj, dtype):
        print("call `__get__` method")
        print("obj : {}".format(obj))
        print("dtype: {}".format(dtype))
        return self._value  
 
    def __set__(self,  obj, value):
        if value 
        
            这样,描述器number作为Apple类的一个属性,在创建新的Apple实例apple=Apple(10)的时候,self.price = 10便会触发描述器的__set__方法, 监测price参数是否为正数,并在不符合条件的时候引发异常。
        
        
            同样,当我们执行print(apple.price)时,dot操作符会触发描述器的__get__方法,执行删除操作的时候会触发描述器的__delete__方法。
        
        
            这样,我们就通过定义描述器的方式,改变了对象的属性在赋值、删除和访问时的默认行为,描述器的功能正在于此。
        

            

                    05
                            
            

                    扩展
                            
                
            
1.Python内置的             staticmethod, classmethod, property,super
等方法也都是描述器,具体的时候可以查看相应的文档            
        
        
            2.实例和类的dotted lookup 优先级有所不同,所以描述器在被类和实例调用时的行为也略有不同,参见Python文档。
        
        

                参考资料
                    
        
            https://docs.python.org/zh-cn/3/howto/descriptor.html
        

            
                https://zhuanlan.zhihu.com/p/52708890
            
            

                    往期推荐