python描述符

描述符定义

       描述符是一种类,我们把实现了__get__()、__set__()和__delete__()中的其中任意一种方法的类称之为描述符。

       描述符的作用是用来代理一个类的属性,需要注意的是描述符不能定义在被使用类的构造函数中,只能定义为类的属性,它只属于类的,不属于实例,我们可以通过查看实例和类的字典来确认这一点。

       描述符是实现大部分Python类特性中最底层的数据结构的实现手段,我们常使用的@classmethod、@staticmethd、@property、甚至是__slots__等属性都是通过描述符来实现的。它是很多高级库和框架的重要工具之一,是使用到装饰器或者元类的大型框架中的一个非常重要组件。注:装饰器和元类等概念我们在以后文章中说明。

      如下示例一个描述符及引用描述符类的代码:

class Descriptors:
 
    def __init__(self, key, value_type):
        self.key = key
        self.value_type = value_type
 
    def __get__(self, instance, owner):
        print("执行Descriptors的get")
        return instance.__dict__[self.key]
 
    def __set__(self, instance, value):
        print("执行Descriptors的set")
        if not isinstance(value, self.value_type):
            raise TypeError("参数%s必须为%s"%(self.key, self.value_type))
        instance.__dict__[self.key] = value 
 
    def __delete__(self, instance):
        print("执行Descriptors的delete")
        instance.__dict__.pop(self.key) 
 
class Person:
 
    name = Descriptors("name", str)
    age = Descriptors("age", int)
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
 
person = Person("xiaoming", 15)
print(person.__dict__)
person.name
person.name = "jone"
print(person.__dict__)

 

        其中,Descriptors类就是一个描述符,Person是使用描述符的类。

        类的__dict__属性是类的一个内置属性,类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里。

        在输出描述符的变量时,会调用描述符中的__get__方法,在设置描述符变量时,会调用描述符中的__set__方法。

        如上例子的运行结果如下:

 

描述符的种类和优先级

       描述符分为数据描述符和非数据描述符。

       至少实现了内置__set__()和__get__()方法的描述符称为数据描述符;实现了除__set__()以外的方法的描述符称为非数据描述符。

      描述符的优先级的高低顺序:类属性 > 数据描述符 > 实例属性 > 非数据描述符 > 找不到的属性触发__getattr__()。

      在上述“描述符定义”章节的例子中,实例person的属性优先级低于数据描述符Descriptors,所以在赋值或获取值过程中,均调用了描述符的方法。

      如下例子描述了类属性高于数据描述符:

class Descriptors:
    def __get__(self, instance, owner):
        print("执行Descriptors的get")
    def __set__(self, instance, value):
        print("执行Descriptors的set")
    def __delete__(self, instance):
        print("执行Descriptors的delete")
 
class University:
    name = Descriptors()
    def __init__(self, name):
            self.name = name
 
University.name
University.name = "深圳大学"
print(University.name)
 
my_university = University("厦门大学")
my_university.name
print(my_university.name)

 

    在该例子中,University类的变量被赋值,由于该优先级最高,所以使用的一直为University类的变量,示例运行结果如下:

    如果在这个例子中,删除University.name = "深圳大学"这一行,则打印是怎么样的?

     为什么对象的name属性没有值了呢,因为对象的的优先级没有描述符高,所以使用描述符的值,而描述符没有赋值,所以为None,所以虽然对象的属性有值,仍然无法正常获取。

     描述符相关的优先顺序,理解难度稍微大一点,请各位看官仔细品味,大家可以自己写小例子尝试打印结果,可以让您更快的理解该原理。

 

参考:https://blog.csdn.net/chenzhanhai/article/details/84350403

 

posted @ 2020-10-20 22:30  腹肌猿  阅读(148)  评论(0编辑  收藏  举报