起因是前两天在煎蛋看到这个段子:
所以我就问了下友人们,什么是“非数据描述符”,然后友人给了我这个:
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,我突然不想知道什么是“非数据描述符”了……
祝友人新婚快乐……