python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 get
, set
, 和 __delete__
。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。
__dict__
作用:字典类型,存放本对象的属性,key(键)即为属性名,value(值)即为属性的值,形式为{attr_key : attr_value}
对象属性的访问顺序:实例属性 → 类属性 → 父类属性 → getattr()方法
class Test(object):
cls_val = 1
def __init__(self):
self.ins_val = 10
>>> t=Test()
>>> Test.__dict__
mappingproxy({'__module__': '__main__', 'cls_val': 1, '__init__': <function Test.__init__ at 0x0000000002E35D08>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None})
>>> t.__dict__
{'ins_val': 10}
>>> type(t)==Test
True
#更改实例t的属性cls_val,只是新增了该属性,并不影响类Test的属性cls_val
>>> t.cls_val = 20
>>> t.__dict__
{'ins_val': 10, 'cls_val': 20}
>>> Test.__dict__
mappingproxy({'__module__': '__main__', 'cls_val': 1, '__init__': <function Test.__init__ at 0x0000000002E35D08>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None})
#更改了类Test的属性cls_val的值,由于事先增加了实例t的cls_val属性,因此不会改变实例的cls_val值(井水不犯河水)
>>> Test.cls_val = 30
>>> t.__dict__
{'ins_val': 10, 'cls_val': 20}
>>> Test.__dict__
mappingproxy({'__module__': '__main__', 'cls_val': 30, '__init__': <function Test.__init__ at 0x0000000002E35D08>, '__dict__': <attribute '__dict__' of 'Test' objects>, '__weakref__': <attribute '__weakref__' of 'Test' objects>, '__doc__': None})
从以上代码可以看出,实例t的属性并不包含cls_val,cls_val是属于类Test的。
__get__
, __set__
, __delete__
他们的原型分别为:
class Desc(object):
def __get__(self, instance, owner):
print("__get__...")
print("self : \\t\\t", self)
print("instance : \\t", instance)
print("owner : \\t", owner)
print('='*40, "\\n")
def __set__(self, instance, value):
print('__set__...')
print("self : \\t\\t", self)
print("instance : \\t", instance)
print("value : \\t", value)
print('='*40, "\\n")
class TestDesc(object):
x = Desc()
#以下为测试代码
t = TestDesc()
t.x
#以下为输出信息:
# __get__...
# self : <__main__.Desc object at 0x0000000002B0B828>
# instance : <__main__.TestDesc object at 0x0000000002B0BA20>
# owner : <class '__main__.TestDesc'>
可以看到,实例化类TestDesc后,调用对象t访问其属性x,会自动调用类Desc的 __get__方法,由输出信息可以看出:
在这里, Desc类就是是一个描述符(描述符是一个类哦),为啥呢?因为类Desc定义了方法 get, set.