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

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

数据描述符与非数据描述符_第1张图片


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


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.name

print("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):
        pass

class 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,我突然不想知道什么是“非数据描述符”了……

祝友人新婚快乐……



你可能感兴趣的:(python,数据描述符,非数据描述符)