流暢的python:描述符

描述符:描述符類的實例是託管類的類屬性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>))
相關文章
相關標籤/搜索