描述符:描述符類的實例是託管類的類屬性spa
用於研究描述符行爲的幾個方法:code
def cls_name(obj_or_cls): cls = type(obj_or_cls) if cls is type: cls = obj_or_cls return cls.__name__.split('.')[-1] def display(obj): cls =type(obj) if cls is type: return '<class {}>'.format(obj.__name__) elif cls in [type(None), int]: return repr(obj) else: return '<{} object>'.format(cls_name(obj)) def print_args(name, *args): persudo_args = ','.join(display(x) for x in args) print('-> {}.__{}__({}))'.format(cls_name(args[0]), name, persudo_args)) class Overriding: """由get 和set 方法的數據描述符,也稱覆蓋型描述符""" def __get__(self, instance, owner): print_args('get', self, instance, owner) def __set__(self, instance, value): print_args('set', self, instance, value) class OverridingNoGet: """沒有get方法的數據描述符,也稱覆蓋型描述符""" def __set__(self, instance, value): print_args('set', self, instance, vvalue) class NonOverriding: """沒有set方法的非數據描述符,也稱非覆蓋型描述符""" def __get__(self, instance, owner): print_args('get', self, instance, owner) class Managed: over = Overriding() over_no_get = OverridingNoGet() non_over = NonOverriding() def spam(self): print('-> Managed.spam({})'.format(display(self)))
覆蓋型描述符,也叫數據型描述符orm
>>> from demo import * >>> m = Manged() >>> m.over #get裏的參數分別對應[self]Overriding實例, [instance]Managed實例,[owner]Managed類 -> Overriding.__get__(<Overriding object>,<Managed object>,<class Managed>)) >>> Managed.over #類直接調用屬性,instance的位置爲None。 -> Overriding.__get__(<Overriding object>,None,<class Managed>)) >>> m.over = 7 #[self]->Overriding的實例, [instance]->Managed類的實例,[value]->設置的值[7] -> Overriding.__set__(<Overriding object>,<Managed object>,7)) >>> m.over #讀取m.over, 仍是出發__get__方法 -> Overriding.__get__(<Overriding object>,<Managed object>,<class Managed>)) >>> m.__dict__['over'] = 8 #直接經過__dict__方法設置實例屬性 >>> vars(m) #__dict__屬性中已經有了over屬性 {'over': 8} >>> m.over #可是,實現了set方法的覆蓋型描述符會跳過實例屬性,直接讀取描述符屬性 -> Overriding.__get__(<Overriding object>,<Managed object>,<class Managed>))
沒有get方法的覆蓋型描述符get
>>> m.over_no_get #沒有__get__方法,因此返回描述符實例 <demo.OverridingNoGet object at 0x7fb0fd793b70> >>> Managed.over_no_get #直接從託管類Managed中讀取描述符實例也是如此 <demo.OverridingNoGet object at 0x7fb0fd793b70> >>> m.over_no_get = 7 #設置值時出發__set__方法 -> OverridingNoGet.__set__(<OverridingNoGet object>,<Managed object>,7)) >>> m.__dict__['over_no_get'] = 7 #經過實例的__dict__屬性設置名爲over_no_get的實例屬性 >>> m.over_no_get #如今,實例屬性會覆蓋描述符,由於沒有定義__get__方法 7 >>> m.over_no_get = 7 #設置屬性值時仍是會觸發描述符的__set__方法 -> OverridingNoGet.__set__(<OverridingNoGet object>,<Managed object>,7))
非覆蓋型描述符,也叫非數據描述符it
>>> m.non_over #出發描述符的__get__方法 -> NonOverriding.__get__(<NonOverriding object>,<Managed object>,<class Managed>)) >>> m.non_over = 7 #沒有__set__方法,因此沒有干涉賦值操做。這裏設置的是實例屬性 >>> m.non_over #實例屬性會覆蓋描述符的__get__方法 7 >>> m.__dict__ {'non_over': 7} >>> Managed.non_over #類的描述符依然存在 -> NonOverriding.__get__(<NonOverriding object>,None,<class Managed>)) >>> del m.non_over #刪除實例屬性 >>> m.__dict__ {} >>> m.non_over #再讀取m.non_over時就會出發描述符的__get__方法 -> NonOverriding.__get__(<NonOverriding object>,<Managed object>,<class Managed>))