数据描述符与非数据描述符

来源:互联网 发布:dx修复软件 编辑:程序博客网 时间:2024/06/04 23:21

起因是前两天在煎蛋看到这个段子:



所以我就问了下友人们,什么是“非数据描述符”,然后友人给了我这个:


class A(object):    name = "haha1"print("此时A这个类的name属性是haha1")print(A.name)print("a是A的实例")a = A()print("这里虽然是输出了haha1, 但是实际上a并没有这个name属性, 而是因为向上搜索到了类的属性, 所以'继承'了出来")print(a.name)## print("这里的'赋值', 显然不会'覆盖'掉类A的属性, 而是给对象a增加了一个name属性, 并且把值赋成haha2")a.name = "haha2"print("类A的name属性不会变")print(A.name)print("对象a得到了name属性")print(a.name)print("删除a的name属性")del a.nameprint("a没有了属性name, 因此再次去'继承'其类的name属性")print(a.name)print("\n************************************************\n")## 实现一个特殊类, 并定义__get__和__set__方法class TestDescriptor(object):    def __get__(self, obj, type = None):        pass    def __set__(self, obj, val):        passclass B(object):    ## 把类B的一个属性设置成上面特殊类的对象    name = TestDescriptor()## print("实例化类B")b = B()print("类B有name属性, 是上面那个特殊类的对象, 但却输出None")print(B.name)print("对象b没有name属性, 应该'继承'类B的属性, 但却输出None")print(b.name)## print("给对象b增加name属性haha3")b.name = "haha3"print("对象b新增了name属性, 值为haha3, 但却输出None")print(b.name)print("\n************************************************\n")## 在上面的特殊类的基础上, 增加一些__get__和__set__的输出class TestDescriptor2(object):    def __get__(self, obj, type = None):        print("get is called.")    def __set__(self, obj, val):        print("set is called.")class B2(object):    ## 把类B的一个属性设置成上面特殊类的对象    name = TestDescriptor2()## print("实例化类B")b2 = B2()print("类B有name属性, 是上面那个特殊类的对象, 但却输出None, 实际在获取类B的name属性时, 调用了特殊类的__get__方法")print(B2.name)print("对象b没有name属性, 应该'继承'类B的属性, 但却输出None, 实际在获取类B的name属性时, 调用了特殊类的__get__方法")print(b2.name)print("给对象b增加name属性haha3, 在设置对象b的name属性时, 调用了特殊类的__set__方法")b2.name = "haha3"print("对象b新增了name属性, 值为haha3, 但却输出None, 还是调用了特殊类的__get__方法")print(b2.name)print("\n************************************************\n")## 在上面的特殊类的基础上, 再增加一些返回class TestDescriptor3(object):    def __init__(self):        self.temp = '';    def __get__(self, obj, type = None):        print("get is called.")        return self.temp + " -> after get"    def __set__(self, obj, val):        print("set is called.")        self.temp = val + " -> after set"        print(self.temp)class B3(object):    ## 把类B的一个属性设置成上面特殊类的对象    name = TestDescriptor3()## print("实例化类B")b3 = B3()print("给对象b增加name属性haha3, 在设置对象b的name属性时, 调用了特殊类的__set__方法")print("调用了__set__, 于是特殊类的selt.temp被赋值")b3.name = "haha3"print("对象b新增了name属性, 值为haha3, 但却输出None, 还是调用了特殊类的__get__方法")print("调用了__get__, 于是特殊类的selt.temp再次被赋值")print(b3.name)## 综上, 在这个特殊类中, 可以对'获取'和'设置'对象的属性做一些中间工作, 这个特殊的中间类, 就被称作数据描述符## 下面是网上抄的定义## 在访问属性的过程中, 遵循一个优先级顺序## 1. 类## 2. 数据描述符## 3. 对象## 4. 非数据描述符## 5. def __getattr__(self, attr) 方法## 实现了__get__, __set__, __del__方法的类属性, 叫做数据描述符## __get__标准定义是 __get__(self, obj, type=None) 三个参数分别为实例/访问方法/None## __set__标准定义是 __set__(self, obj, val) 三个参数分别为实例/访问方法/set的值## __del__标准定义是 __del__(self, obj) 两个参数分别为实例/访问方法print("\n************************************************\n")## 根据上面的这个定义, 实例数据是可以覆盖非数据描述符的, 但不可以覆盖数据描述符## 只有__get__, 是非数据描述符class C1(object):    def __get__(self, obj, type = None):        print("get is called.")## 有__get__和__set__, 是非数据描述符class C2(object):    def __get__(self, obj, type = None):        print("get is called.")    def __set__(self, obj, val):        print("set is called.")class D1(object):    name = C1()class D2(object):    name = C2()d1 = D1()print("给对象d1设置name属性的值")d1.name = "haha5"print("实例数据覆盖了非数据描述符, 不会调用__get__")print(d1.name)d2 = D2()print("给对象d2设置name属性的值")d2.name = "haha5"print("实例数据不能覆盖数据描述符, 继续调用__get__")print(d2.name)


好吧……我不会python,我突然不想知道什么是“非数据描述符”了……

祝友人新婚快乐……



原创粉丝点击