Python描述符深入理解
阿新 • • 發佈:2018-12-24
Python的描述符乍眼看去簡單,但是細節方面如果不注意容易掉坑,總結以下幾個坑,以作備忘,先看程式碼:
class D: def __get__(self, inst, owner): if inst is None: return self else: print('I am in the D.__get__') return inst.__dict__['d'] # 返回例項的d屬性 def __set__(self, inst, value): if not isinstance(value, str): raise AttributeError('Value must be str') print('I am in the D.__set__') inst.__dict__['d'] = value # 設定例項自身d屬性,只能使用__dict__形式,否則又會呼叫__get__,從而陷入無限迴圈 class C: d = D() def __init__(self, value): self.d = value # 在初始化的時候設定d屬性,注意此時呼叫__get__函式,並不是設定例項本身的屬性 >>> c = C('shy') I am in the D.__set__ >>> c.__dict__ {'d': 'shy'} >>> c.d I am in the D.__get__ 'shy'
總結:
- 描述符只能做類屬性,不能作為例項屬性,當一個屬性是描述符時,例項查詢這個屬性會直接在類裡面查詢而忽略例項自身的空間,如上,例項自身有同名的d屬性,但是當通過c.d呼叫的時候,呼叫的是描述符d。
- 在描述符裡獲取或者設定例項的同名屬性時,需要用inst.__dict__形式訪問,上面如果寫成inst.d,則會陷入無限迴圈。
再來看一段程式碼:
class D: def __get__(self, inst, owner): if inst is None: return self else: print('I am in D.__get__') return self.value def __set__(self, inst, value): print('I am in D.__set__') self.value = value class C: d = D() >>> c1 = C() >>> c2 = C() >>> c1.d = 2 I am in D.__set__ >>> c2.d = 3 I am in D.__set__ >>> c1.d I am in D.__get__ 3 >>> c2.d I am in D.__get__ 3 class D: def __get__(self, inst, owner): if inst is None: return self else: print('I am in D.__get__') return inst.value def __set__(self, inst, value): print('I am in D.__set__') inst.value = value class C: d = D() >>> c1 = C() >>> c2 = C() >>> c1.d = 2 I am in D.__set__ >>> c2.d = 3 I am in D.__set__ >>> c1.d I am in D.__get__ 2 >>> c2.d I am in D.__get__ 3
總結:
屬性可以儲存在描述符內部,也可以儲存在例項,但是如果儲存為描述符內部,則為所有例項共享,所以一般把描述符的狀態的資訊儲存在描述符內部,而把例項相關的資訊儲存在例項側。