描述符的本質就是新式類,其至少實現了__get__(),__set__(),__delete__()中的一個,也被稱爲描述符協議;
__get__():在調用一個屬性時,觸發
__set__():在爲一個屬性賦值時,觸發
__delete__():在用del刪除屬性時,觸發
描述符的作用:用來代理另一個類的類屬性(必須是類屬性,不能在類的函數構造中),且描述符在自身調用,賦值,刪除屬性時不會被觸發
class Str:
def __get__(self, instance, owner):
print('觸發Strget',instance,owner)
def __set__(self, instance, value):
print('觸發Strset',instance,value)
def __delete__(self, instance):
print('觸發Strdel')
class Int:
def __get__(self, instance, owner):
print('觸發Intget',instance,owner)
def __set__(self, instance, value):
print('觸發Intset',instance,value)
def __delete__(self, instance):
print('觸發Intdel')
class People:
name=Str()
age=Int()
def __init__(self,name,age):
self.name=name
self.age=age
#自身的實例不會觸發
s=Str()
s.x=1
del s.x
i=Int()
i.y=2
del i.y
#實例化people時觸發
p=People('alex',18)
#描述符Str的使用
p.name
p.name='Bart'
del p.name
#描述符Int的使用
p.age
p.age=19
del p.age
print(p.__dict__)#爲空,因爲name和age屬性被Str和Int代理,在Str和Int中處理,並沒有寫入p.__dict__中
print(People.__dict__)
描述符分兩種一 數據描述符:
1.數據描述符:至少實現了__get__()和__set__()
2. 非數據描述符:沒有實現__set__()
注意:
一 描述符本身應該定義成新式類,被代理的類也應該是新式類
二 必須把描述符定義成這個類的類屬性,不能爲定義到構造函數中
三 要嚴格遵循該優先級,優先級由高到底分別是
1.類屬性
2.數據描述符
3.實例屬性
4.非數據描述符
5.找不到的屬性觸發__getattr__()
class Str:
def __get__(self, instance, owner):
print('觸發Strget',instance,owner)
def __set__(self, instance, value):
print('觸發Strset',instance,value)
def __delete__(self, instance):
print('觸發Strdel')
class People:
name=Str()
def __init__(self,name):
self.name=name
#類屬性>數據描述符>實例屬性
#數據符大於實例屬性
p=People('Alex')#觸發了__set__
p.name #觸發了__get__
p.name='Bart' #觸發了__set__
del p.name #觸發了__delete__
print(p.__dict__)
#類屬性大於數據描述符
print('====>',People.__dict__['name'])
People.name='Bart'#不會觸發__set__,直接People.__dict__中name對應的值由__set__的內存地址改爲Bart
print('====>',People.__dict__['name'])
print(p.name) #不再觸發__get__
class Str:
def __get__(self, instance, owner):
print('觸發Strget',instance,owner)
# def __set__(self, instance, value):
# print('觸發Strset',instance,value)
# def __delete__(self, instance):
# print('觸發Strdel')
class People:
name=Str()
def __init__(self,name):
self.name=name
#實例大於非數據描述符
p=People('Alex')
p.name
p.name='Bart'
#都不會觸發
描述符的作用
描述符可以規定輸入的值的類型
class Type:
def __init__(self,key,type):
self.key=key
self.type=type
def __get__(self, instance, owner):
print('觸發get')
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('觸發set')
if not isinstance(value,self.type):
raise TypeError('%s不是%s'%(value,self.type))
else:
instance.__dict__[self.key]=value
def __delete__(self, instance):
print('觸發del')
class People:
name=Type('name',str)
age=Type('age',int)
salary=Type('salary',float)
def __init__(self,name,age,salary):
self.name=name
self.age=age
self.salary=salary
p1=People("alex",18,3000.0)
print(p1.__dict__)
p2=People('bart','18',3000)