国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Python屬性、方法和類管理系列之----描述符類

2019-11-14 17:02:55
字體:
來源:轉載
供稿:網友

什么是描述符類?

根據鴨子模型理論,只要具有__get__方法的類就是描述符類。
如果一個類中具有__get____set__兩個方法,那么就是數據描述符,。
如果一個類中只有__get__方法,那么是非數據描述符。

__get__:當我們用類或者實例來調用該屬性時,Python會返回__get__函數的結果。
__set__:當我們用實例來設置屬性值時,Python會調用該函數。對類沒有限制作用。
__delete__:當我們用實例試圖刪除該屬性時,Python會調用該函數。對類沒有限制作用。

非數據描述類

class Desc:    def __init__(self, value=22):        self.value= value    def __get__(self, ins, cls):        return self.valueclass A:    v=Desc()a=A()

上面的描述符類只有一個__get__屬性,所以是非數據描述符。

>>> a.v             #由于實例中沒有v屬性,所以找到了類的屬性,而類的屬性是一個描述符類實例,所以調用其__get__方法的結果。22>>> a.__dict__      #實例的__dict__空空如也。{}>>> A.__dict__      #類的__dict__中確實存在v屬性,且是一個Desc object對象。mappingPRoxy({'__module__': 'b', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__dict__': <attribute '__dict__' of 'A' objects>, '__doc__': None, 'v': <b.Desc object at 0x7ff010f5f550>})>>> a.v=30          #我們通過實例設置v屬性,發現成功了。>>> a.__dict__      #我們發現實例的__dict__中存入了我們剛才設置的屬性{'v': 30}>>> A.__dict__      #類的__dict__沒有發生任何變化mappingproxy({'__module__': 'b', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__dict__': <attribute '__dict__' of 'A' objects>, '__doc__': None, 'v': <b.Desc object at 0x7ff010f5f550>})>>> a.v             #如我們所料,訪問到了a.__dict__中的內容。             30>>> del a.v         #我們刪除實例的屬性v后發現居然還是可以調用a.v,返回的是我們設置之前的值。>>> a.v22>>> A.__dict__      #和前面一樣,沒有發生變化。mappingproxy({'__module__': 'b', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__dict__': <attribute '__dict__' of 'A' objects>, '__doc__': None, 'v': <b.Desc object at 0x7ff010f5f550>})

通過上面的測試,我們發現非數據描述類有如下特點:

  • 如果實例__dict__沒有設置同名屬性,那么返回描述類的__get__方法的結果。
  • 如果實例__dict__中存在同名屬性,那么返回實例__dict__中的內容。
  • 對我們設置實例的__dict__中的行為并不做阻止。所以我說這是查看級別的描述類。

數據描述類

class Desc:    def __init__(self, value=22):        self.value= value    def __get__(self, ins, cls):        return self.value    def __set__(self, ins, value):        self.value=value        #raise AttributeErrorclass A:    v=Desc()a=A()

運行結果如下:

>>> a.v22>>> a.v=10>>> a.__dict__      #我們設置a.v后,發現實例的__dict__中仍然空空如也。因為此時調用的是__set__方法,值10存入到了Desc實例的value屬性上了。{}>>> A.__dict__mappingproxy({'__module__': 'b', '__doc__': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, 'v': <b.Desc object at 0x7f0d2a4de5c0>})>>> a.v             #此時得到的還是Desc的__get__方法返回的結果。10>>> del a.v         #不允許我們刪除Traceback (most recent call last):  File "<stdin>", line 1, in <module>AttributeError: __delete__>>> A.v=30>>> A.__dict__mappingproxy({'__module__': 'b', '__doc__': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, 'v': 30})#我們把__set__方法的原來語句注銷,添加raise AttribeError語句,再次運行>>> a.v=30          #我們在__set__中手動添加了AttributeError異常,所以我們再也不能設置a.v的值了,因此該屬性鞭策了只讀屬性。Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "/home/aaa/proj/b.py", line 8, in __set__    raise AttributeErrorAttributeError>>> A.v=20          #通過類,仍然可以改變屬性>>> A.__dict__      #改變后,變成了普通屬性20了,這時甚至都已經不再是描述符類了。mappingproxy({'__doc__': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__module__': 'b', '__weakref__': <attribute '__weakref__' of 'A' objects>, 'v': 20})>>> del A.v

說明如下:

  • __set__方法存在后,實例設置同名屬性時,完全需要看__set__的臉色。
  • 如果描述類中__set__方法存在但是__delete__方法不存在,那么不能刪除客戶類中的屬性。
  • 即使在__set__方法中做了限制,這個限制只是對實例而言的,對類沒有起到作用。

把屬性存在描述符類中

class Desc:    def __init__(self, value):        self.value = value    def __get__(self, ins, cls):        return self.value    def __set__(self, ins, value):        self.value = value    def __delete__(self, ins):        raise AttributeError('not allowed to delete attribute name ' )class A:    name=Desc('JS')a=A()

執行結果如下:

>>> del a.name>>> a=A()>>> b=A()>>> a.name'JS'>>> b.name'JS'>>> a.name='CC'>>> b.name'CC'Traceback (most recent call last):  File "<stdin>", line 1, in <module>  File "/home/aaa/proj/b.py", line 10, in __delete__    raise AttributeError('not allowed to delete attribute name ' )AttributeError: not allowed to delete attribute name

缺點顯而易見,如果有多個實例,那么他們共享一個描述符,所以當一個實例的該屬性發生改變后,其他實例的該屬性也會發生變化。

改善方法:
存入一個字典,把實例的hash作為健存入,這樣可以解決問題。

class Desc:    def __init__(self, value):        self.values={}    def __get__(self, ins, cls):        return self.values[hash(ins)]     def __set__(self, ins, value):        self.values[hash(ins)]=value    def __delete__(self, ins):        raise AttributeError('not allowed to delete attribute name ' )

把數據存入實例中

class Desc:    def __get__(self, ins, cls):        return ins._name    def __set__(self, ins, value):        ins._name=value     def __delete__(self, ins):        raise AttributeError('not allowed to delete attribute name ' )class A:    name=Desc()a=A()

執行結果如下:

>>> a=A()>>> a.name='JS'>>> a.name'JS'>>> a._name='CC'>>> a.name'CC'

缺點:我們設置在實例中的變量私密性不太好,可以很容易被改變。
當然,可以做一個私有性的裝飾器,或者利用屬性擴張來解決,這是我在后面會介紹的內容。

補充解釋

__get__(self, ins, cls):其中ins為實例對象,在我們上面的例子中是a或者b,cls為a或者b的類,為A
__set____delete__:ins和上面的含義相同


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 舒城县| 涟源市| 汤原县| 璧山县| 锡林浩特市| 灵台县| 曲阜市| 江北区| 延庆县| 无锡市| 海安县| 沙坪坝区| 西安市| 本溪| 新平| 株洲县| 湘潭市| 玉屏| 潼南县| 铁岭县| 三江| 通城县| 集安市| 蓬溪县| 宁南县| 新和县| 台湾省| 资溪县| 长宁县| 兴仁县| 洞口县| 蒙山县| 白玉县| 威远县| 溧水县| 隆回县| 乡城县| 台北市| 玛多县| 衡水市| 常州市|