python属性描述符和属性查找过程

attr_describe
 
 
#coding:utf-8
#属性描述符和属性查找过程
#属性描述符分为两种:1,数据属性描述符。2,非数据属性描述符
import numbers
#只要实现下面3个方法中的任何一个,IntField就是属性描述符
class IntField:
    #数据属性描述符
    def __get__(self,instance,owner):
        return self.value #这个value就是下面自己定义的
    #在__set__做参数类型的检查
    def __set__(self,instance,value):
        if not isinstance(value,numbers.Integral):
            raise ValueError("int value need")
        if value<0:
            raise ValueError("positive value need")
        #instance.age=value 不能这么存放值,因为这种属性赋值的方法会循环调用__set__方法
        self.value=value#将值放在了IntField类里面,前面一个value是自己命名的,随便叫什么都可以
    def __delete__(self,instance):
        pass

class NonDataIntField:
    #非数据属性描述符
    def __get__(self,instance,owner):
        return self.value

class User:
    #age=IntField()#age是一个数据属性描述符的对象
    age=NonDataIntField()
"""
属性查找过程:
如果user是某个类的实例,那么user.age(以及等价的getattr(user,'age'))首先调用__getattribute__。
如果类定义了__getattr__方法,那么在__getattribute__抛出AttributeError的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则发生在__getattribute__内部的。
user=User(),那么user.age顺序如下:
(1)如果“age”出现在User或其基类(父类)的__dict__中,且age是data descriptor,那么调用其__get__方法,否则
(2)如果“age”出现在user的__dict__中,那么直接返回obj.__dict__['age'],否则
(3)如果“age”出现在User或其基类(父类)的__dict__中,
(3.1)如果age是non-data descriptor,那么调用其__get__方法,否则
 (3.2)返回__dict__['age']
(4)如果User有一个__getattr__方法,调用__getattr__方法,否则
(5)抛出AttributeError
"""
if __name__ == "__main__":
    user=User()
    user.age=20  #当age是数据属性描述符时,对其赋值的时候,会调用IntField中的__set__方法,该值进入IntField的value中,而不会进入user的__dict__中
    user.__dict__['age']='abc'
    print(user.__dict__)#__dict__方法用来查询属性,当age是非数据属性描述符时,age就会进入user的属性中:{'age': 20}
    print(user.__dict__['age'])# abc
    print(user.age)# 因为age是数据属性描述符,使用user.age的时候还是会调用IntField中的value值,而不会调用user的属性值abc
    print(getattr(user,'age'))

猜你喜欢

转载自blog.csdn.net/jiangsujiangjiang/article/details/85228575