# 描述符覆盖行为

# 描述器分类

descr.__get__(self, obj, type=None) -> value
descr.__set__(self, obj, value) -> None
descr.__delete__(self, obj) -> None

同时定义__get__()​ 和 __set__()​的称为数据描述器或强制描述符。

仅定义 __get__()​的称为非数据描述器或遮盖型描述符。

仅定义 __set__()​的称为覆盖型描述符,没有定义__set__​的称为非覆盖描述符。

# 覆盖型描述符和非覆盖型描述符

# 覆盖性描述符

覆盖性描述符:实现了__set__​​方法的描述符

  • 没有实现__get__​​方法的话

    • 如果实例属性空间__dict__​中有同名属性,则获取时会被实例属性空间中的同名属性覆盖,但是赋值时还是被__set__​接管

      print(man.over_no_get)      # <__main__.OverridingNoGet object at 0x000002009326F6C8>
      man.over_no_get = "MMMMM"   # -> OverridingNoGet.__set__(<OverridingNoGet object>, <Managed object>, <str object>)
      man.__dict__["over_no_get"] = "man-over_no_get"
      print(man.over_no_get)      # man-over_no_get
      man.over_no_get = "MMMMM"   # -> OverridingNoGet.__set__(<OverridingNoGet object>, <Managed object>, <str object>)
      print(man.over_no_get)      # man-over_no_get
      
  • 实现了__get__​​方法

    • 明显,获取和赋值都会被接管

# 非覆盖描述符

非覆盖描述符:没有实现__set__​方法的描述符

因为没有实现__set__​所以只要产生赋值操作都会在实例属性空间中创建同名属性,之后再获取或者赋值都走属性空间

print(man.non_over) # -> NonOverriding.__get__(<NonOverriding object>, <Managed object>, <class Managed>)
                    # None
man.non_over = "NNNNN"
print(vars(man))    # {'non_over': 'NNNNN'}
print(man.non_over) # NNNNN
man.__dict__["non_over"] = "man-non_over"
print(man.non_over) # man-non_over
man.non_over = "NNNNN" 
print(man.non_over) # NNNNN

# 总结

总的来说,python按照以下顺序查找属性

  1. MRO顺序中的类的类属性中的数据描述符
  2. 实例属性空间中的同名属性
  3. MRO顺序中的类的类属性中的非数据描述符
  4. MRO顺序中的类的类属性中的普通属性