python之属性描述符与属性查找规则

描述符
import numbers
class IntgerField:
    def __get__(self, isinstance, owner):
        print('获取age')
        return self.num
    
    def __set__(self, instance, value):
        print('设置age值时')
        if  not isinstance(value, numbers.Integral):
            raise ValueError('int need')
        self.num = value
    def __delete__(self, instance):
        pass


class User:
    age = IntgerField()   // 数据属性描述符,查找优先级最高


user = User()
user.age = 33
print(user.age)


上述的User可以看做数据库中的表,假设我们要控制user中age的赋值类型,固然可以使用以下形式进行拦截:

class User:
    age = 33
    def __setattr__(self, name, value):
        pass               // 这里进行类型检测
又或者:
class User:
    @property
    def age(self):
        return self._num
    @age.setter
    def age(self,value):
        self._num = value // 这里进行类型检测

但是这种一两次还行,多了就是在写重复代码,所以就可用上述类IntgerField中定义__get__,__set__等实现属性描述符的方式进行拦截。
getattributegetattrsetattr、__delattr__等方法用来实现属性查找、设置、删除的一般逻辑,而对属性的控制行为就由属性对象来控制。这里单独抽离出来一个属性对象,在属性对象中定义这个属性的查找、设置、删除行为。这个属性对象就是描述符。
描述符对象一般是作为其他类对象的属性而存在。在其内部定义了三个方法用来实现属性对象的查找、设置、删除行为。这三个方法分别是:
get(self, instance, owner):定义当试图取出描述符的值时的行为。
set(self, instance, value):定义当描述符的值改变时的行为。
delete(self, instance):定义当描述符的值被删除时的行为。
其中:instance为把描述符对象作为属性的对象实例;
owner为instance的类对象。

描述符有数据描述符和非数据描述符之分

只要至少实现__get__、set、__delete__方法中的一个就可以认为是描述符;
只实现__get__方法的对象是非数据描述符,意味着在初始化之后它们只能被读取;
同时实现__get__和__set__的对象是数据描述符,意味着这种属性是可读写的。

属性查找规则

当查找对象上的某个属性时,假设是user.age,顺序先是判断该实例所指向的类以及基类的__dict__中查找,并且如果该属性数据属性描述符,就会调用描述符中的__get__方法
如果该age直接出现在obj.__dict__上,直接返回obj.__dict__['age']
如果该属性出现在User中或基类中,且该属性是非数据属性描述符,就会调用其__get__方法,如果不是非数据属性描述符,就会调用User或基类的User或基类.__dict__['age']
如果这些都没有,且User上也没有__getattr__方法,就会报错

猜你喜欢

转载自www.cnblogs.com/raind/p/10146160.html
今日推荐