Python Descriptor描述符02
说明
- 使用描述符时,实例对象的属性访问会触发描述符的__get__方法
- 使用描述符时,实例对象的属性赋值会触发描述符的__set__方法
- 通过obj.__dict__[xxx]=yyy 赋值会跳过描述符
- 没有__get__方法的覆盖描述符,给对象的属性赋值会触发__set__方法,读取属性时会直接从实例中返回新赋予的值,而不会返回描述符对象, 也就是说读取操作实例属性会遮盖描述符,直接从__dict__中获取
- 非数据描述符中,如果设置了同名的实例属性,描述符会被遮盖,致使描述符无法处理那个实例的那个属性,即获取属性的值将直接通过__dict__中获取
- 类属性赋值能覆盖描述符属性,如果想控制设置类属性的操作,需要把描述符依附在类的类上,即依附在元类上
- 类中定义的函数属于绑定方法,因为用户定义的函数都有get方法,所以依附到类上,相当于描述符,为非覆盖性描述符
概念描述
- 描述符类: 实现描述符协议的类
- 托管类: 把描述符实例声明为类属性的类
- 描述符实例: 描述符类的各个实例,声明为托管类的类属性
- 托管实例:托管类的实例
- 储存属性: 托管实例中存储自身托管属性的属性
- 托管属性: 托管类中由描述符实例处理的公开属性,值存储在储存属性中, 也就是说,描述符实例和储存属性为托管属性建立了基础
描述符实例
|
|
描述符实例重构
|
|
覆盖型和非覆盖型描述符对比
覆盖型描述符 实现了__set__方法的描述符,实现了set方法会覆盖对实例属性的赋值操作
非覆盖型描述符 没有实现__set__方法的描述符是非覆盖型描述符,如果设置了同名的实例属性,描述符会被遮盖,致使描述符无法处理那个实例的那个属性
类属性赋值能覆盖描述符属性,如果想控制设置类属性的操作,需要把描述符依附在类的类上,即依附在元类上
|
|
描述符用法
- 使用特性以保持简单
- 只读描述符必须有__set__方法,如果需要实现只读属性,get和set方法必须都实现,否则实例的同名属性会遮盖描述符,只读属性的__set__方法只需抛出AttributeError异常,并提供合适的错误信息
- 用于验证的描述符可以只有__set__方法
- 仅有get方法的描述符可以实现高效缓存,同名实例属性会遮盖描述符
- 非特殊的方法可以被实例属性遮盖, 函数和方法都只实现了get方法,不会处理同名实例属性的赋值操作
以上内容学习记录参照《流畅的python》 第20章 属性描述符